C#SocketAsyncEventArgs处理接收和发送数据

时间:2012-01-26 13:06:59

标签: c# sockets tcp socketasynceventargs

我试图理解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进行接收并循环处理接收数据,然后在需要发送时从池中分配SocketAsyncEventArgs然后在完成时返回它?

SocketAsyncEventArgs在读取完成时如何知道? (当它在用新数据覆盖它之前完成了byte []缓冲区),如果我没有回复,它如何在完成时返回到池中?

1 个答案:

答案 0 :(得分:8)

我只使用一个SocketAsyncEventArgs实例来满足我的所有需求。我只是在每个请求之间重置缓冲区(通过将其设置为新的Byte [])。

一旦我连接并引用了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字节整数来表示消息。如果需要,我可以详细说明。

希望有所帮助。