我正在尝试理解C#中的"SocketAsyncEventArgs"类。http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.aspx
我正在学习本教程:http://www.codeproject.com/Articles/83102/C-SocketAsyncEventArgs-High-Performance-Socket-Cod
现在,我陷入了应该如何使用服务器处理数据的困境。我正在尝试为连接的客户端使用SocketAsyncEventArgs,该客户端在BufferManager中分配了512字节的缓冲区空间。然后,我想做的是将byte[]数据解码到我自己的自定义类(ClientPacket)中,该类保存用于解码和读取的byte[]。
这一切都很好,但我的服务器并不总是用数据回应,问题是:
我是否使用1个SocketAsyncEventArgs进行接收并循环处理接收数据,然后在需要发送时从池中分配一个Socket异步EventArgs,然后在完成时返回?
SocketAsyncEventArgs如何知道读取何时完成?(当它在用新数据重写之前用byte[]缓冲区完成时),比如如果我没有响应,它在完成时如何返回到池?
我只使用一个SocketAsyncEventArgs实例来满足所有需求。我只是在每个请求之间重置缓冲区(通过将其设置为新的Byte[])。
一旦我连接并引用了套接字,我就开始这样听:
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.BytesTransfered值来指示实际接收的数据量,该数据量可能小于但永远不会超过缓冲区大小(我的代码中为SocketBufferSize)。如果消息大于缓冲区大小,TCP基础结构将缓冲消息,并根据SocketBufferSize(通过为每个块引发一次事件)将消息分块发送给您。如果这是一个问题,只需增加SocketBufferSize,直到在一个块中接收到大部分消息。
分块的缺点是消息可能会被基础设施合并,这意味着你可能需要一种方法来判断第一条消息何时结束。典型的方法包括在消息前面加一个4字节的整数,表示消息长度。如果需要,我可以详细说明。
希望能有所帮助。