mtu取值范围(mtu值范围)

TCP和UDP的流量控制和包大小以及MTU的关系

以太网帧MTU最小为64字节,最大为1518字节,对于小于或者大于这个范围的都称为错误帧,一般的以太网转发设备都会丢弃这些错误帧。

TCP:

TCP将要发的数据放在发送缓冲区,将接受的数据放在接收缓冲区。当应用程序就绪时,他就从接收缓冲区读取数据,如果接收缓冲区满了,接收器将不会接收更多数据并且将其丢弃。因此为了保证可以接受数据,接收方会告诉发送方当前还剩多少空间(接收窗口)进行流量控制。协议栈并不是一收到数据就马上发送,而是将这些分散的数据放在内部的发送缓冲区中,因为发送大量的小包会导致网络效率下降,他会等到你应用程序的下段数据,直到你的发送缓冲区积累到一定数量再发送出去。

至于积累多少数据才会发送出去,第一个判断要素是网络包的最大数据长度,协议栈叫MTU. 在以太网层为1500字节,减去头部就是TCP的最大数据长度,减去TCP和IP的头部40个字节,得到的1460字节(MSS)就是你可以达到不分包进行发送的最大数据长度。什么叫分包,大家都知道因为IP包的最大长度是65535字节,理论上支持65495字节,因为MTU为1500,因此需要IP模块进行分片,再在接收端进行IP模块的组合。如果发生组包错误,包会重传,这个不像UDP,错误就会丢弃。所以为了避免在组包过程中发生错误,你控制你的TCP数据包为1460(MSS)就不会发生组包了

正式因为TCP引入了MSS,他的正常大小是MTU-40=1460字节,如果通信双方没有指定MSS的话,默认的MSS是536字节。MTU是IP协议物理设备的上限,而MSS是操作系统内核层面的限制,会在TCP三次握手的时候确定这个MSS,一旦确定了MSS,TCP就会对你应用层交给TCP协议的数据进行分包构成多个数据段,从而避免IP层出现过多分包。注意,这个TCP根据MSS的分包对你来说也是透明的。其中IP层对话的是Package, 数据链路层对话的是帧,TCP层对话的是数据段(Segment)

因此由于TCP没有“包长度”的概念,他完全依托IP层去分帧,这也是解释他是一种“流协议”的原因,开发者在使用TCP的时候不需要去考虑其大小,只管往里塞数据即可,TCP协议本身会去做拥塞和流量控制

因此TCP存在将多个小包合并到一起发送(解决网络带宽效率问题),那么你在应用层就需要去处理这种粘包问题。有效的措施你可以加入比如length数据。UDP不会存在粘包,因为UDP发送的时候没有经过Negal算法优化,他不会把多个小包合并一次发送出去。另外在UDP协议的接收端,采用链式结构记录了每一个到达的UDP包,这样应用程序的每一次recv只能读取一个数据包。也就是说你发送了几次,接收端必须recv几次,这个就和TCP的多次发送,实际最终可能发送一次,产生本质区别。

TCP也存在最小字节的问题,TCP的最小字节为46-IP头(20)-TCP头(20)=6字节,看下46字节的由来

mtu取值范围(mtu值范围)

UDP:

首先基于IP层的协议,IP层最大支持65535个字节,减去IP头(20)和UDP头(8),那么最大可以发送65507个字节,一旦你超过了这个字节,函数就会返回错误。当然本身这个长度也已经大于了MTU的1500,因此会进行分包再组包,但是如果组包失败,UDP会直接丢弃,因此为了避免组包过程中带来的错误,建议你的UDP包长度不要超过MTU,一般建议不超过1K。因此为了保证正常,在用UDP发送的情况下,因为他没有重传机制,为了避免组包产生问题而造成丢包,我们一般会控制在1500以下以及576(Internet)以下进行发送,然后把分包组包的任务放到我们应用层去做。

不过在非局域网(Internet)上的标准MTU只有576,因此如果你采用的是UDP编程的方式,如果在Internet环境下,最好把其长度控制在548(576-8-20)字节。如果是在局域网内,你就应该考虑只发送65535-IP头(20)-UDP头(8)=65507字节,否则你的sendto()会返回失败

mtu取值范围(mtu值范围)

此外UDP还有最小有效数据的问题,即你的数据包也不能太小,比如你就想发个Hello World,不满足最小有效数据(64-46)=18字节,但是为什么对方仍然能收到,就是因为在链路层的MAC子层帮你做了数据补齐。不足18个字节的帮你以0做补齐,但如果你的服务器在公网,客户端在内网,如果你发送小于18字节的数据,对方可能会出现接收不到的情况。

mtu取值范围(mtu值范围)

mtu取值范围(mtu值范围)

mtu取值范围(mtu值范围)

本文内容源自网友投稿,多成号仅提供信息存储服务不拥有所有权。如有侵权,请联系站长删除。qq97伍4伍0叁11