发送大于SendBufferSize的数据时,如何接收数据?

我刚刚问了一个关于如何发送大于SendBufferSize的数据的问题,答案是将在几个部分发送。

我的第二个问题是这些数据将如何收到? 它会在网络流中完成还是会被分割。

第一个问题: 你能发送一个比TcpClient更大的SendBufferSize文件吗?

TCP不是仅消息协议。 它是一个基于流的协议,负责为我们分割数据。 Lemme带你到核心部分。 在TCP的情况下有两个部分 – 分段和分段。

分段发生在TCP(传输层)。 这取决于两个参数 – MSS和窗口大小。 MSS确定设备可以接收的段的最大大小。 通过TCP选项在初始连接建立期间传送MSS。 数据流的每个方向都可以使用不同的MSS,操作系统会对其进行确定。 但是,窗口大小由接收器在TCP报头中发送,以便在等待来自接收主机的确认和窗口更新之前,在连接的接收侧上一次缓冲它可以缓冲的最大数据。 也就是说,主机可以在耗尽接收器的窗口大小之前发送多个段(MSS因子)。

碎片以两种方式发生在IP(网络层)。 如果在发送方和接收方之间的通信路径上没有对MTU限制的设备,则会发生碎片以满足以太网的MTU(1500字节)。 然而,由于存在发送器和接收器之间具有MTU限制的中间设备,IP层(因特网协议)进行数据报碎片,因此可以形成分组以使得它们可以通过具有较小最大传输单元的链路( MTU)比原始数据报大小。 在具有MTU限制的中间设备的情况下,发送方还应部署路径MTU发现以确定到接收机的网络路径中的最小MTU并动态调整MSS以避免网络内的IP分段。 通过在传出数据包的IP头中设置DF(不分段)选项来完成路径MTU发现。 发送方和接收方之间的通信路径中的任何设备(其MTU小于数据包)将丢弃此类数据包并使用包含设备MTU的ICMP“目标无法到达(数据报太大)”消息回复发送方。 此信息允许发送方适当地减少其假定的路径MTU。

因此,这导致了MSS和MTU之间的关系点。 RFC 791规定“所有主机必须准备接受最多576个八位字节的数据报(无论它们是全部还是碎片到达)”。 因此,IP网络的最小MTU为576.在TCP的情况下,TCP报头减去20字节,IP报头减去20字节,我们将为TCP提供536字节作为标准MSS。

现在,让我们进入重新组装部分。 碎片可能基于中间设备上的MTU发生,但重新组装仅在目标设备上发生。 TCP负责分段,但是在目标设备上,TCP应该负责排序,但是应该由应用程序来重新组装段。

因此,如果您只需要基于整个消息的通信并且可靠性不是问题,那么UDP将是您的选择。 但是,请注意,如果您可以通过拆分发送大数据,UDP将无法确保数据包的排序,也无法处理数据包丢弃,因为它没有像重新传输那样的纠错机制。

如果您希望像在UDP中一样进行基于消息的通信,但又需要TCPfunction,例如可靠的有序传送,拥塞控制以及其上的其他改进/function,例如多流,多宿主,以及建立MTU发现,那么SCTP应该是您的选择。 但是,如果您的网络中有旧版NAT系统,则可能需要在UDP中封装SCTP。

与例如UDP相反,TCP不是允许发送单个“消息”的协议,其以相同的forms传送到接收器。 您宁愿发送和接收字节流。

在引擎盖下,你的数据被分成IP数据包, 无论 SendBufferSize ,btw默认为8192,这个数值远远高于单个IP数据包(IP数据包的最大大小与MTU有关 ,但主要是少于1500字节)。 例:

  1. Socket.Send(2000字节)
  2. IP数据包#1(1460字节)
  3. IP数据包#2(540字节)

另外:多个Socket.Send()的数据可能会被合并( Nagle的算法 )。 例:

  1. Socket.Send(1000字节)
  2. Socket.Send(1000字节)
  3. IP数据包#1(1460字节)
  4. IP数据包#2(540字节)

并且接收器无法区分这两种情况。 更重要的是,出于效率的原因,在接收端,数据可能会在不同大小的缓冲区中移交给您。

底线:使用TCP,您不能依赖于接收与发送的数量相同且大小相同的数据包。 如果您需要,请按照Stephen Cleary的建议添加大小信息,或者使用UDP等协议,或者如果您需要可靠性: SCTP 。 然而,除非您对SCTP对TCP的其他改进感兴趣,否则这看起来有点矫枉过正。

.Net处理为您分割数据。 您可以编写和接收大于SendBufferSize的包,而不会注意到它(如果您不太关心性能)。

您需要在协议中使用称为消息框架的内容。

有趣的事实:即使发送小于SendBufferSize的消息,您也需SendBufferSize 。 🙂

有可能您的数据将在接收时被拆分,因此您需要在收到所有数据后重建它。