IP协议分片&&重组问题
IP数据报分片的主要目的是为了防止IP数据报文长度超过下一跳链路(最大传输单元)。
分片是什么&&为什么会有分片
IP数据报分片的主要目的是为了防止IP数据报文长度超过下一跳链路MTU(最大传输单元)。
数据链路层之MTU
-
数据链路层中有一个东西叫做MTU(最大传输单元),它的作用主要是控制上层给的数据报不要太大,大的数据报文在网络内传输时会占用过多带宽资源,使其它报文的转发效率下降,通过MTU来限制数据报文,根据MTU将数据报文分片以减少数据碰撞的发生。
-
每种数据链路的最大传输单元 MTU 都是不相同的,如 FDDI 数据链路 MTU 4352、以太网的 MTU 是 1500 字节等。
-
每种数据链路的 MTU 之所以不同,是因为每个不同类型的数据链路的使用目的不同。使用目的不同,可承载的 MTU 也就不同。
-
其中,我们最常见数据链路是以太网,它的 MTU 是 1500 字节。
-
那么当 IP 数据包大小大于 MTU 时, IP 数据包就会被分片。
-
经过分片之后的 IP 数据报在被重组的时候,只能由目标主机进行,路由器是不会进行重组的。
-
假设发送方发送一个 4000 字节的大数据报,若要传输在以太网链路,则需要把数据报分片成 3 个小数据报进行传输,再交由接收方重组成大数据报。即1500,1500,1000三个数据报
工作原理
IP报文特性
IP 包全长由头部中的 总长度 字段决定,该字段共 16 位,因此一个 IP 包最大可达 65535 字节。除去头部 20 字节,IP 包最多可承载 65515 字节的数据:
如果IP 头部带有可选选项,长度就不止 20 字节了,但最大60字节。以上关于IP报文详细结构可以看这篇。,同理,数据的携带就会相应变少。
在观察IP数据报文的特性之后我们发现:
- 一个 65535 字节的 IP 报文,显然不可能在运输能力只有 1500 字节的以太网帧或任意一个数据链路层协议帧中。
发送端分片简单原理
我们从上至下讲:
- TCP报文询问IP,IP询问数据链路层MTU是多少,数据链路层返回1500。
- IP得到MTU=1500,因为IP报头需要最少20字节,所以,给TCP的回复是1480。
- TCP得到回复MTU=1280,由于TCP报头最少要20字节,故根据MTU,TCP留给数据的空间就是1460字节。
- TCP再根据对端发来的接收端窗口大小,if 接收端窗口.size() < MTU.size() ,则最终TCP数据报文的大小 = 接收端窗口大小,else TCP数据报文的大小 = 1460。
- 说到这里大致就明朗了,IP其实没有进行分片的机会!!!为什么呢?
- 主要是因为分片降低网络性能
-
TCP在传输层通过滑动窗口以及和对端商量好了发送数据的大小,你IP又在网络层分一次,干嘛不直接在传输层做完呢,这就可以提高效率了。TCP两件事都给做了,这个过程叫做分段。
-
另外,如果IP分片了,数据在传输过程中出现了丢包,可TCP是IP的上层,是不知道IP分片了,分了几片的,所以触发了超时重传等机制,TCP就不得不把整个丢失的包进行重发,但实际丢掉的是IP分片之后的一部分数据包。那么,网络设计者觉得与其让IP分片,不如TCP把这事做了,丢包了也只需要重传一小部分,而不是像上面那样重传整个数据包。
-
同时,如果在IP分片,每一个分片又得带上相差无几的报头,浪费!
-
所以,不如在传输层全部做好,IP只需要做一件事情——>添加自己的报头,转发报文给数据链路层就完成工作了!!!
-
所以,TCP把分片的工作给抢了,这种机制叫做MSS(最大分段大小),防止IP分片
故此,提出一个概念:
- IP协议负责数据包的地址标注与传输,他是传输策略的执行者
- TCP协议则建立连接,管理流量和错误校验,保证了数据传输的可靠性,他是传输策略的制定者
-
- 主要是因为分片降低网络性能
发送端分片详细原理
这里强烈建议去熟悉IP报文结构
IP 包头部中有 3 个与分片相关的字段,分别是:
- 16位标识: IP 包的 ID ,全局自增,短时间内不会重复,主机发送的报文的唯一标识. 如果IP报文在数据链路层被分片了, 那么每一个片里面的这个id都是相同的.
- 3位标志位:
- 第一位:DF - Don’t Fragment 位,为1表示禁止分片, 这时候如果报文长度超过MTU, IP模块就会丢弃报文.
- 第二位:MF - More Fragments 位,该位用于指示报文是否有后续分片。如果分片了的话, 最后一个分片置为0, 其他是1, 类似于一个结束标记。
- 第三位:Fragment Offset 位,这些位标识分片在原始报文中的相对位置。它们与分片序号一起,用于重组时排序和定位分片。
- 13位片偏移: 是分片相对于原始IP报文开始处的偏移. 其实就是在表示当前分片在原报文中处在哪个位置. 实际偏移的字节数是这个值 * 8 得到的. 因此, 除了最后一个报文之外, 其他报文的长度必须是8的整数倍(否则报文就不连续了).
- 这里解释一下为什么是13位片偏移:
IP报头中的片偏移字段只有13位,如果以字节为单位,其能表示的偏移范围是:
2^13 = 8191字节 = 8KB
而IP数据报的总长度字段有16位,可以表示的总长度是:
2^16 = 65535字节 = 64KB
以字节为偏移单位,13位能表示的最大偏移量是8KB,如果数据报大于8KB,偏移字段会出现表示不足的情况。
但偏移量以8字节为单位,13位就可以表示:
8192 * 8 = 64KB
正好与总长度字段的表示范围相同。
所以出于表示范围的限制,偏移字段必须采用“以8字节为单位”的设计,即使最小分片也会多占用一点空间,这是对范围表示和分片处理的一个综合考量。
- 这里解释一下为什么是13位片偏移:
假设发送端通过以太网帧 MTU 是 1500 ,它准备发一个长度为 4000 字节的 IP包。TCP分片情况如下:
如上图,原包长达 4000 字节,其中头部 20 字节,数据部分为 3980 字节。分片包最大长度为 1500 ,除去头部的 20 字节,数据部分只剩 1480 。这意味着,原包 3980 字节至少需要分为 3 片。
由于偏移量字段以 8 字节为单位,因此每个分片的数据长度必须为 8 的倍数,最后一片除外。由于 1480 刚好可以被 8 整除,因此分片数据长度可以选择 1480 。
第一个分片,包含原包前 1480 字节数据,因此偏移量 offset=0 ;而 MF=1 表示后面还有其他分片。第二个分片,包含原包紧接着的 1480 字节数据,偏移量 1480/8=185 ;同样 MF=1 表示后面还有其他分片。最后一个分片,包含原包最后 1020 字节数据,偏移量 29608/8=370 ;而 MF=0 表示它是最后一片了。
接收端是如何重组IP报文的
这些分片被发出去后,由于是不同的数据包,可能出现丢包,阻塞等现象,到达时间和顺序是无法预测的,所以,无法按照分片到达顺序来确定。
因此,分片到达目标主机后,系统根据报头中字段,将它们重组。
实际上,系统会分配一块内存作为重组分片的缓冲区。一个分片包首个分片达到后,系统将其移入到该缓冲区,等待其他分片达到:
后续分片达到后,系统先根据源地址、目的地址和标识符确定它属于哪个包;再根据偏移量确定它属于原包的哪个部分;最后将分片数据拼接到原包中。当所有分片都到达后,原包也就成功重组出来了!
IP是否有可能分片
如果中间路由链路 MTU 变小,经过的 IP 包大小超出限制,路由便再次对 IP 包进行分片。就算 IP 包已分过片,只要有分片大小超出限制,都要进一步划分(注意按照现在的讲法IP此时是可以分片的):
如上图,路由专线的 MTU 很小。一个去往主机A的 IP 包,被主机A发出前已被分为两片。来到路由器1 时,由于第一个分片大小仍超过路由器的 MTU ,路由器1 进一步将其分为两片。
IP 包来到 路由2 后链路 MTU 变大,理论上可以对前两个分片进行组装,还原出原来的分片 1 。但出于效率考虑,中间路由不会这么做,分片只有到达目的地即主机B之后,才会开始重组。
但我们说过,IP分片会导致效率的下降 ,那么如何让IP分不了包呢?(以下PMTU内容参考小白debug)
- 获取 PMTU(整个IP报文传输过程中设备数据链路层的最小MTU)!!!
- 使用 IP 报头中的3位标志位
- IP 包设置 DF 标志,中间路由便不能将它分片,只能向发送者报告 ICMP 目的不可达 错误。
- ICMP中包含PMTU信息,TCP获取PMTU后,重新组织数据段发送,以此避免IP分片!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)