【问题标题】:BeginReceive/SocketAsyncEventArgs list of ArraySegmentsBeginReceive/SocketAsyncEventArgs ArraySegments 列表
【发布时间】:2017-03-09 15:33:47
【问题描述】:

ArraySegment<byte>列表 传递给Socket.BeginReceive/SocketAsyncEventArgs 背后的原因是什么?

MSDN for the Socket.BeginReceive constructor 甚至没有正确描述第一个参数):

public IAsyncResult BeginReceive(
    IList<ArraySegment<byte>> buffers,
    SocketFlags socketFlags,
    AsyncCallback callback,
    object state
)

参数:
缓冲区
类型:System.Collections.Generic.IList&lt;ArraySegment&lt;Byte&gt;&gt;
Byte 类型的数组,它是接收数据的存储位置。
...

我认为主要的想法是在大对象堆上分配一个大缓冲区,然后将这个缓冲区的一部分传递给Socket.BeginReceive,以避免将小对象钉在堆周围并弄乱GC的工作。

但我为什么要向这些方法传递几个段?如果是SocketAsyncEventArgs,似乎会使这些对象的池化变得复杂,我不这样做看不出这背后的原因。

【问题讨论】:

    标签: garbage-collection socketasynceventargs beginreceive


    【解决方案1】:

    我在 this question 和 MSDN 中发现的:

    1. BeginReceive 有一个重载版本,它采用字节数组。当它已满或已接收到数据包(逻辑上按顺序)时,将触发回调。

    2. 正如我链接的答案中所述:

    读取可以是它的倍数,因为如果数据包无序到达,那么在逻辑上第一个到达的那一刻,所有这些都对应用程序可见。在这种情况下,您可以一次读取所有连续排队的数据包。

    这意味着:如果有一个乱序的传入数据包(即序列号高于预期的序列号),它将被保留。一旦丢失的数据包到达,所有可用的数据包都会写入您的列表,并且只有一个回调会被触发,而不是为所有已经可用的数据包一遍又一遍地触发回调,每个数据包都会填充您的缓冲区尽可能,等等。

    这意味着,这个实现通过在数组列表中提供所有可用的数据包只调用回调一次而不是从网络堆栈到缓冲区执行大量内存复制,从而节省了大量开销反复给你回电。

    【讨论】:

      猜你喜欢
      • 2014-03-06
      • 1970-01-01
      • 2011-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-28
      • 1970-01-01
      相关资源
      最近更新 更多