【问题标题】:C# Async Sockets: How much data does the Socket store when the call to BeginReceive is delayed?C# Async Sockets:延迟调用 BeginReceive 时 Socket 存储多少数据?
【发布时间】:2017-09-12 00:35:07
【问题描述】:

我正在使用 C# 的异步套接字并使用 BeginReceive 将数据从 Socket 读取到 8192 字节的 byte[]-Buffer 中。但是,在再次调用 BeginReceive 之前有新数据包进来时会发生什么?我当前的设置在停止之前处理大约 3 条传入消息。我假设 Socket 必须先将传入的数据存储在某处,然后才能被 BeginReceive 处理。

我是否可以控制 Socket 在停止之前缓冲多少数据?

我是否必须依靠足够快的速度处理传入的消息才能不“错过”任何消息?

当下面示例中的 ProcessMessageBuffer 方法花费很长时间(由于某种原因)以至于传入的数据开始堆积在 Socket 中时会发生什么?

public void ReadCallback(IAsyncResult ar)
    {
        // We have a new TCP Packet!
        int bytesReceived = 0;

        try
        {
            // The amount of bytes we have just received
            bytesReceived = Socket.EndReceive(ar);
        }
        catch (SocketException ex)
        {
            // The client closed the connection
            OnSocketException(new SocketExceptionEventArgs(ex));
        }

        if (bytesReceived > 0)
        {
            // We have received some data. Write it to the MessageBuffer
            MessageBuffer.Write(ReceiveBuffer, 0, bytesReceived);

            // Process the Messages that may be stored in the MessageBuffer
            // What happens, if this takes too long?
            ProcessMessageBuffer(MessageBuffer.ToArray());

            // Get ready to receive more data
            Socket.BeginReceive(ReceiveBuffer, 0, ReceiveBuffer.Length, SocketFlags.None, new AsyncCallback(ReadCallback), null);
        }
    }

【问题讨论】:

    标签: c# sockets networking tcp


    【解决方案1】:

    网络 I/O 在每一步都被缓冲。所以很难知道你担心的是哪个“缓冲区”。

    来自Socket.ReceiveBufferSize

    …默认值为 8192。

    较大的缓冲区大小可能会减少空确认(没有数据部分的 TCP 数据包)的数量,但也可能会延迟对连接困难的识别。如果您正在传输大文件,或者您正在使用高带宽、高延迟的连接(例如卫星宽带提供商),请考虑增加缓冲区大小。

    根据您的问题:

    我是否可以控制 Socket 在停止之前缓冲多少数据?

    您至少有几个可用的策略:

    • 修改ReceiveBufferSize 属性值。这将改变套接字对象中缓冲区的大小。
    • 在调用BeginReceive() 时使用更大的缓冲区。这将为Socket 对象提供更多可写入的空间,然后它就不能再清空自己的缓冲区。请注意,您传递给 Socket 的缓冲区将被固定,直到接收操作完成,这可能会对内存堆管理产生影响。
    • 发出多个BeginReceive() 呼叫。这与提供更大的缓冲区具有类似的效果,但可以让您对缓冲区进行更精细的控制。它带来的复杂性是,由于 Windows 调度线程的方式,您最终可能会以与您最初调用 BeginReceive() 的顺序不同的顺序执行接收操作完成的回调。 data 将按照BeginReceive() 调用的顺序和您传递的每个缓冲区的顺序排列正确,但这些缓冲区可能会出现在您的代码中以乱序填充(它们不是t 真的,但处理稍后填充的缓冲区的线程可能会在处理较早填充的缓冲区的线程之前运行)。

    有关更多详细信息,请参阅socket buffer size: pros and cons of bigger vs smaller

    我是否必须依靠足够快的速度处理传入的消息才能不“错过”任何消息?

    没有。 TCP是可靠的。如果您处理数据的速度不够快,将会发生的只是远程端点必须等待发送更多数据。

    也就是说,您应该非常努力地使您的套接字 I/O 代码尽快工作。如果您有一些处理速度慢到足以延迟接收操作,您应该将该处理卸载到一个完全独立的线程,自己缓冲接收到的数据(例如使用MemoryStreamFileStream,某种队列,等等)。

    如果你这样做,那么除了简单的、默认的套接字处理之外,你可能不需要做任何事情。您将能够一次拥有一个未完成的BeginReceive(),您不必调整套接字的缓冲区,并且您将能够分配“正常大小的”byte[] 对象(或保留一个重复使用)。

    【讨论】:

      猜你喜欢
      • 2013-01-03
      • 2015-07-19
      • 1970-01-01
      • 2014-03-30
      • 2019-03-15
      • 1970-01-01
      • 2023-03-17
      • 2021-07-01
      • 2021-01-10
      相关资源
      最近更新 更多