我刚问了一个关于如何发送大于SendBufferSize的数据的问题,答案就是将发送几个部分。
我的第二个问题是这些数据将如何收到?它会在网络流中完成还是会被分割。
第一个问题:Can you send a file larger that the SendBufferSize throuh a TcpClient?
答案 0 :(得分:4)
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小于数据包将丢弃此类数据包,并使用ICMP"目标无法到达(数据报太大)"来回复发送方。包含设备MTU的消息。此信息允许发送方适当地减少其假定的路径MTU。
因此,这导致MSS和MTU之间的关系点。 RFC 791规定"所有主机必须准备好接受最多576个八位字节的数据报(无论它们是全部还是碎片)"。因此,IP网络的最小MTU为576.在TCP的情况下,TCP报头减去20个字节,IP报头减去20个字节,我们将给出536个字节作为TCP的标准MSS。
现在,让我们进入重新组装部分。碎片可能基于中间设备上的MTU发生,但重新组装仅在目标设备上发生。 TCP负责分段,但是在目标设备上,TCP应该负责排序,但应该由应用程序来重新组装段。
因此,如果您只需要基于整个消息的通信并且可靠性不是问题,那么UDP将是您的选择。但请注意,如果您可以通过拆分发送大数据,UDP将无法确保数据包的排序,也无法处理数据包丢弃,因为它没有像重新传输那样的纠错机制
如果您希望像UDP一样进行基于消息的通信,但又需要TCP功能,如可靠的有序传送,拥塞控制以及其他更多改进/功能,如多流,多宿主,内置MTU发现,然后SCTP应该是你的选择。但是,如果您的网络中有传统的NAT系统,那么您可能需要在UDP中封装SCTP。
答案 1 :(得分:3)
与例如UDP,TCP不是允许发送单个“消息”的协议,这些消息以相同的形式传送到接收器。您宁愿发送和接收字节流。
在幕后,你的数据被分成IP数据包,无论 SendBufferSize
,btw默认为8192,这个值远高于单个IP数据包( IP数据包的最大大小与MTU相关,但大多数小于1500字节)。例如:
另外:多个Socket.Send()
的数据可能会合并(Nagle's algorithm)。例如:
并且接收器无法区分这两种情况。更重要的是,出于效率的原因,在接收端,数据可能会以不同的大小缓冲区移交给您。
底线:使用TCP,您不能依赖于接收与发送的数量相同且大小相同的数据包。如果您需要,请按照Stephen Cleary的建议添加大小信息,或者使用UDP等协议,或者如果您需要可靠性:SCTP。然而,这看起来有点矫枉过正,除非您对SCTP对TCP的其他改进感兴趣。
答案 2 :(得分:2)
.Net为您处理数据分割。您可以编写和接收大于SendBufferSize的包,而不会注意到它(如果您不太关心性能)。
答案 3 :(得分:1)
您的协议中需要一个名为message framing的内容。
有趣的事实:即使发送的邮件小于SendBufferSize
,您也需要这样做。 :)
答案 4 :(得分:0)
您的数据可能会在接收时被拆分,因此您需要在收到所有数据后重建它。