private void ProcessReceive(SocketAsyncEventArgs e)
{
// Check if the remote host closed the connection.
if (e.BytesTransferred > 0)
{
if (e.SocketError == SocketError.Success)
{
Token token = e.UserToken as Token;
token.SetData(e);
Socket s = token.Connection;
if (s.Available == 0)
{
Boolean willRaiseEvent = false;
// GET DATA TO SEND
byte[] sendBuffer = token.GetRetBuffer();
// this.bufferSize IS SocketAsyncEventArgs buffer SIZE
byte[] tempBuffer = new byte[this.bufferSize];
int offset = 0;
int size = (int)Math.Ceiling((double)sendBuffer.Length / (double)this.bufferSize);
for (int i = 0; i < size - 1; i++)
{
Array.Clear(tempBuffer, 0, this.bufferSize);
Array.Copy(sendBuffer, offset, tempBuffer, 0, this.bufferSize);
e.SetBuffer(tempBuffer, 0, this.bufferSize);
willRaiseEvent = s.SendAsync(e);
offset += this.bufferSize;
}
int remainSize = sendBuffer.Length - this.bufferSize * (size - 1);
Array.Clear(tempBuffer, 0, this.bufferSize);
Array.Copy(sendBuffer, offset, tempBuffer, 0, remainSize);
e.SetBuffer(tempBuffer, 0, remainSize);
willRaiseEvent = s.SendAsync(e);
if (!willRaiseEvent)
{
this.ProcessSend(e);
}
}
else if (!s.ReceiveAsync(e))
{
// Read the next block of data sent by client.
this.ProcessReceive(e);
}
}
else
{
this.ProcessError(e);
}
}
else
{
this.CloseClientSocket(e);
}
}
This code is modified from MSDN
Why in circulation, execute s.SendAsync(e)
the second time, it will be error
Exception:An asynchronous socket operation is already in progress using this SocketAsyncEventArgs instance
How can I send large data ?
You have to wait for the Completed
event to be raised before you can make another asynchronous send. Don't forget to add your own event handler in order for you to get the callback:
e.Completed += new EventHandler<SocketAsyncEventArgs>(SendCallback);
You can use my example of an Asynchronous HTTP client to model yours:
private void BeginSend()
{
_clientState = EClientState.Sending;
byte[] buffer = GetSomeData(); // gives you data for the buffer
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.SetBuffer(buffer, 0, buffer.Length);
e.Completed += new EventHandler<SocketAsyncEventArgs>(SendCallback);
bool completedAsync = false;
try
{
completedAsync = _socket.SendAsync(e);
}
catch (SocketException se)
{
Console.WriteLine("Socket Exception: " + se.ErrorCode + " Message: " + se.Message);
}
if (!completedAsync)
{
// The call completed synchronously so invoke the callback ourselves
SendCallback(this, e);
}
}
Here is the callback method:
private void SendCallback(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
// You may need to specify some type of state and
// pass it into the BeginSend method so you don't start
// sending from scratch
BeginSend();
}
else
{
Console.WriteLine("Socket Error: {0} when sending to {1}",
e.SocketError,
_asyncTask.Host);
}
}
After the callback is complete, you can make another call to BeginSend
again, until you're done sending data.
The problem is not that you have to wait until Completed
is raised. I think, it is also not the purpose of async programing to wait for any event.
But the SocketAsyncEventArgs
can only be reused if the last action is completed. So, you can resolve the issue just by create a new SocketAsyncEventArgs
within each loop.
Another solution: you may use blocked socket, this return after completition or error, but it must be in another thread.
来源:https://stackoverflow.com/questions/9170126/how-to-use-socket-sendasync-to-send-large-data