我只使用一个 SocketAsyncEventArgs 实例来满足我的所有需求。我只是在每个请求之间重置缓冲区(通过将其设置为新的字节 [])。
一旦我连接并引用了 Socket,我就开始像这样听:
public void StartListening(SocketAsyncEventArgs e)
{
ResetBuffer(e);
e.Completed += SocketReceive;
socket.ReceiveAsync(e);
}
我有一个重置缓冲区的辅助函数:
private void ResetBuffer(SocketAsyncEventArgs e)
{
var buffer = new Byte[SocketBufferSize];
e.SetBuffer(buffer, 0, SocketBufferSize);
}
我处理数据如下:
private void SocketReceive(Object sender, SocketAsyncEventArgs e)
{
ProcessData(e.Buffer, 0, e.BytesTransferred);
ResetBuffer(e);
socket.ReceiveAsync(e);
}
在 ProcessData 中,您可以根据需要使用字节数组来拉入数据。我用它来创建一个 MemoryStream,然后我将它反序列化到我的类中(类似于 ClientPacket),如下所示:
private void ProcessData(Byte[] data, Int32 count)
{
using (var stream = new MemoryStream(data, 0, count))
{
var serializer = new XmlSerializer(typeof(ClientPacket));
var packet = serializer.Deserialize(stream);
// Do something with the packet
}
}
至于你的最后一个问题。该框架处理与底层 TCP 协议等有关的所有事情,因此您可以依赖在有数据要处理时调用的事件处理程序。使用 e.BytesTransferred 值来指示您实际收到的数据量,它可能小于但永远不会超过您的缓冲区大小(我的代码中的 SocketBufferSize)。如果消息大于缓冲区大小,则 TCP 基础结构将缓冲消息并根据 SocketBufferSize 将它们以块的形式发送给您(通过为每个块引发一次事件)。如果这是一个问题,只需增加 SocketBufferSize 直到您的大部分消息都以一个块的形式收到。
分块的缺点是消息可能会被基础设施合并,这意味着您可能需要一种方法来判断第一条消息何时结束。典型的方法包括在您的消息前加上一个 4 字节整数来指示消息长度。如果需要,我可以详细说明。
希望有帮助。