分片是什么&&为什么会有分片

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字节为单位”的设计,即使最小分片也会多占用一点空间,这是对范围表示和分片处理的一个综合考量。

假设发送端通过以太网帧 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分片!
    在这里插入图片描述
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐