详解TCP/IP重组
Posted 写程序的康德
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了详解TCP/IP重组相关的知识,希望对你有一定的参考价值。
学习网络应用开发的时候最大的疑惑是“分片”。几乎在TCP/IP的每一层都有这个概念,由于专注这方面的资料非常少所以对这部分内容很多朋友多云山雾绕的,这篇文章总结了我关于TCP/IP分片、重组的一些认识,希望对大家有帮助。
MTU
按不同的网络传输介质和传输算法网络有不同的种类,比如令牌环、FDDI、ATM、以太网。其中以太网最为普遍——几乎成为了网络的代名词,所以我们所能接触到的所有网络几乎都是以太网。以太网的传输介质是铜缆、双绞线、光纤;传输算法是CSMA/CD,按照这个算法规定数据并不是“源源不断”的发送出去的,而是每次发送“一小段”,发送完毕后要检测是否冲突。MTU(Maximum Transmission Unit,最大传输单元)就是指“一小段”数据有多大。按照IEEE802.3(以太网技术的标准化名称)规范MTU的最大值是64字节、最大长度是1518字节。IEEE之所以选择这两个值是为了考虑到线路的利用率,以10Mbps为例(以太网最早的标准),最大传输距离是500m,做多允许中继4次,所以它最大允许2500m的传输距离。
数据在这个距离上跑个一来一回需要57.6μs,在这个时间内A一共可以发送576bit也就是72字节。去掉8个字节的前导码和帧开始符(一个帧以7个字节的前导码和1个字节的帧开始符作为帧的开始)也就是64字节。最大值1518字节有点“拍脑袋”的意思,采用这个值可以让线路利用率更高,至于为什么会这样几乎没有人能回答上来(包括以太网之父Bob Metcalfe也说不清楚)
IP重组
可以看到截图中两个IP数据包的id都是22828,其中第一个的flags部分是[+],表示有IP分片并且这是第一个分片。
第一个IP分片完整大小是1500(MTU),去掉IP头(20字节),实际大小是1480(ICMP数据包,包含头部)
第二个IP分片完整大小是48,去掉IP头部(20字节),实际大小是28字节
1480+28=1508,刚好是我们ICMP数据包的大小
这里需要解释IP重组的几个问题
IP只有重组,没有分片。IP数据包头部的MF标志位主要用于解决MTU和IP大小不匹配的问题,用于IP数据包重组,IP数据包从来不会主动分片。
IP没有重传,IP数据包被分为多个帧传输,**如果任何一个帧丢失IP数据包都会重组失败那么整个数据包都会被丢弃**。所以基于IP协议的上层协议一般不会发送超过1500大小的数据包(考虑一下如果用UDP协议发送65535个字节,被拆分成43个MTU大小的帧,收到了42个,其中一个没有收到那么IP数据包重组失败,数据包被彻底丢弃,是不是很浪费带宽?)
TCP的MSS
TCP协议格式中没有一个字段表示数据包大小,它被设计成一个“流式”协议,所以在三次握手的时候会相互交换MSS(Maximum Segment Size 最大分段大小),表示一个TCP分片是多大。那么MSS取值多少合适呢?有了上面的结论IP没有重传不难得出答案——1500最合适。如果TCP数据分片超过这个值会被拆分成多个MTU帧,从而引起IP重组;IP重组本身是不可靠的所以很有可能丢失数据包(最重要的是IP重组失败后不会报告上层协议)要命的是TCP协议不会知道重组失败,也没有办法重传。所以如果我们用tcpdump抓包所有的TCP三次握手MSS都是等于MTU值的。
UDP呢?
长期以来我一直疑惑单个UDP数据包最大值是多少(调用send/recv函数时传递的大小),UDP头部有2个字节表示长度理论上一个UDP数据包最大能够传输65536字节,这个也是IP数据包的最大理论值。有些系统定义了SO_MAX_MSG_SIZE宏来表示这个限制。但是如果UDP数据包真的用这个值那么一定会触发IP重组从而又回到了我们上面的结论IP只有重组没有重传。一个UDP数据包被拆分成43个MTU大小的帧,对端收到了42个,其中一个没有收到那么IP数据包重组失败,数据包被彻底丢弃,如果网络质量不是特别好UDP数据包会经常“丢包”。所以UDP最大数据包值合适的大小是1500-8(UDP包头)=1492。
总结
IP只有重组没有重传,如果任何一个IP包丢失那么就会把整个数据包丢弃。所以TCP用MTU值作为MSS;UDP用1492作为最大值以此来避免IP重组。
以上是关于详解TCP/IP重组的主要内容,如果未能解决你的问题,请参考以下文章