将ArraySegment<byte>
的列表传递给Socket.BeginReceive
/ SocketAsyncEventArgs
背后的原因是什么?
MSDN for the Socket.BeginReceive
constructor甚至没有正确描述第一个参数):
public IAsyncResult BeginReceive(
IList<ArraySegment<byte>> buffers,
SocketFlags socketFlags,
AsyncCallback callback,
object state
)
Paremeters:
缓冲器
输入:System.Collections.Generic.IList<ArraySegment<Byte>>
类型为Byte
的数组,它是接收数据的存储位置 ...
我认为主要的想法是在大对象堆上分配一个大缓冲区,然后将此缓冲区的一部分传递给Socket.BeginReceive
,以避免在堆周围固定小对象并弄乱GC的工作。
但为什么我要将几个段传递给这些方法?如果是SocketAsyncEventArgs
,它似乎会使这些对象的汇集变得复杂,并且我没有看到这背后的原因。
答案 0 :(得分:1)
我在this question和MSDN中发现的内容:
BeginReceive
的重载版本采用字节数组。当它已满或收到数据包时(逻辑上按顺序),将触发回调。
如我在回答中所述:
读取可以是其倍数,因为如果数据包按顺序到达,则在逻辑上第一个到达时,应用程序可以看到所有数据包都可见。在这种情况下,您可以一次性读取所有连续排队的数据包。
这意味着:如果有一个无序的传入数据包(即序列号比预期的更高),它将被保留。一旦丢失的数据包到达,所有可用的数据包都会写入您的列表并且只会触发一个回调,而不是针对已有的所有数据包反复触发回调,每个数据包都将缓冲区填充为尽可能远,等等。
这意味着,这个实现通过在数组列表中提供所有可用数据包来节省大量开销,只调用一次,而不是从网络堆栈到缓冲区执行大量的memcopies反复叫你回电。