BeginReceive/SocketAsyncEventArgs ArraySegments 列表

BeginReceive/SocketAsyncEventArgs list of ArraySegments

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

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

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

Paremeters:
buffers
Type: System.Collections.Generic.IList<ArraySegment<Byte>>
An array of type Byte that is the storage location for the received data.
...

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

但为什么我要将 几个 段传递给这些方法?SocketAsyncEventArgs 的情况下,似乎将使这些对象的池复杂化,我看不出这背后的原因。

我在 this question 和 MSDN 中发现的内容:

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

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

Reads can be multiples of that because if packets arrive out of order all of them are made visible to application the moment the logically first one arrives. You get to read from all contiguous queued packets at once in this case.

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

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