9

我试图理解 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[] 缓冲区时)比如如果我不回复,它在完成后如何返回到池中?

4

1 回答 1

10

我只使用一个 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 字节整数来指示消息长度。如果需要,我可以详细说明。

希望有帮助。

于 2012-01-26T13:31:52.360 回答