如何使用 Socket.SendAsync 发送大型数据
本文关键字:大型 数据 SendAsync 何使用 Socket | 更新日期: 2023-09-27 18:23:38
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);
}
}
此代码是从 MSDN 修改的
为什么在流通中,第二次执行s.SendAsync(e)
,会出错
异常:使用此套接字异步事件参数实例的异步套接字操作已在进行
中
如何发送大数据?
您必须等待引发Completed
事件,然后才能进行另一个异步发送。不要忘记添加自己的事件处理程序,以便获取回调:
e.Completed += new EventHandler<SocketAsyncEventArgs>(SendCallback);
您可以使用我的异步 HTTP 客户端示例来建模:
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);
}
}
下面是回调方法:
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);
}
}
回调完成后,您可以再次调用BeginSend
,直到完成数据发送。
问题不在于你必须等到提出Completed
。我认为,等待任何事件也不是异步编程的目的。
但是,只有在完成最后一个操作后,才能重复使用SocketAsyncEventArgs
。因此,您只需在每个循环中创建一个新SocketAsyncEventArgs
即可解决此问题。
另一种解决方案:您可以使用阻塞的套接字,这在完成或错误后返回,但它必须在另一个线程中。