分片与组装
在网络数据在网络中传播的过程中,如果从一台主机送到另一台主机上,那么在跨网络传输过程中,就需要一个个的路由器进行转发,最终才可以到达目标主机。
就比如下图中,将数据从主机B跨网络传送到主机C,那么主机B需要先将数据交给路由器F,路由器F再将数据交给路由器G ...... 最终由路由器D将数据交给主机C。

因此,IP协议负责跨网络的全局寻址和路由,但它本身并不负责在相邻两点之间的具体传输。其背后,这个"相邻节点间传送"的问题,正是由数据链路层负责解决的。其中数据链路层中代表协议就是MAC帧协议。
最大传输单元 MTU
MAC帧作为数据链路层的核心协议,负责将IP层下发的数据包封装成可在本地网络传输的数据帧。然而,MAC帧所承载的有效载荷长度存在上限,这一限制意味着IP层交付给它的报文不能超过特定大小。该上限值被称为"最大传输单元"(Maximum Transmission Unit,MTU)。在标准以太网中,MTU的典型值为1500字节。
在Linux下可以使用 ifconfig 命令查看其对应的MTU。
所以由于MAC帧协议的规定,无法发送大于1500字节的数据,因此IP协议所在的层向下交付的数据的长度不能超过1500字节,这里所说的数据包括IP协议的报头和IP协议的有效载荷。
分片与组装
如果IP层要传送的数据超过了1500字节,那么就需要先在IP层对该数据进行分片,然后再将分片后的数据交给下层MAC帧进行发送。
如果发送方进行了分片,那么接收方在接收的时候也会进行对应的组装来保证数据的一致性。
- 在网络中,数据的分片于组装不是经常发生的,其实际情况下,不进行分片于组装才是常态,因为数据进行分片存在着一定的风险,比如分片会在一定程度上提高丢包的可能性。
- 数据的分片与组装发生在IP协议所在的层 -- 网络层,但分片其并不是单单发生于端主机与目标主机,还可能发生在路由器与路由器之间,这是因为不同网络下的MTU的值是不同的,如果传输路径上的某个网络的MTU比源端网络的MTU小,那么路由器就可能对IP数据报再次进行分片。
- 但其组装只发生在目标主机上。
- 在分片的过程中,单个报头分为多个后,每段都需要重新添加上新的报头,进行封装。而原本的传输层封装的报头则放置于第一段的报文中,因此网络中的报文并不是每个都拥有传输层封装而来的报头。
其该过程中,对数据的分片与组装,全部是由网络层的IP协议负责,其该过程中上下两层都并不对其关心,上层传输层,下层数据链路层都不对其结果关心。其只需要保证其本身负责的部分的可靠性即可。
分片的过程
假设网络层的IP协议要发送4500字节的数据,由于该数据超过了MAC帧规定的MTU,因此IP协议需要先将该数据进行分片,然后再将一个个的分片交给MAC帧进行发送。
在这里我们默认所有的IP协议的选型部分全为空,即报头默认大小为20字节。
对于此4500字节大小的数据,进行分片。经过计算每个IP的分片的最大有效载荷为1480。
则要将有效载荷分片为1480 + 1480 + 1480 + 60的结构。
至此就为得到如下的分片结构:
| 分片报文 | 总字节数 | IP报头字节数 | 数据字节数 |
|---|---|---|---|
| 1 | 1500 | 20 | 1480 |
| 2 | 1500 | 20 | 1480 |
| 3 | 1500 | 20 | 1480 |
| 4 | 80 | 20 | 60 |
IP协议在发送端对数据进行分片后,接收端的IP层必须能够将这些分片准确重组为原始数据包。为此,IP头部中设计了三个专门用于记录分片信息的字段:16位标识、3位标志和13位片偏移。这些字段共同记录了每个分片在原始数据包中的位置和顺序,是确保数据在接收端能够被正确重组的关键依据。
-
16位标识:用于唯一标识同一主机发出的数据报文。若报文在IP层被分片,则所有分片均共享相同的16位标识值,以便接收端识别并重组属于同一原始报文的分片。
-
3位标志:
-
第一位(保留位):目前未定义具体用途,通常置为0。
-
第二位(DF位,禁止分片):若该位设为1,则指示路由器不得对此报文进行分片。若报文长度超过路径MTU,路由器将丢弃该报文并返回ICMP错误信息。
-
第三位(MF位,更多分片):用于指示分片状态。
-
若报文未分片,该位置0。
-
若报文已分片,则除最后一个分片置0外,其余所有分片均置1,表示后续还有分片需要接收。
-
-
-
13位片偏移:表示当前分片数据在原始报文数据区中的起始位置(以8字节为单位)。实际字节偏移量为该值 × 8。因此,除最后一个分片外,所有分片承载的数据长度必须是8字节的整数倍,以确保分片数据可以按正确偏移量连续重组。
因此,上述的四个分片报文对应的16位标识理应都是一样的,如果四个分片报文的16位标识都是2026,则这四个报文对应的16位标识、3位标志中的"更多分片"和13位片偏移分别如下:
| 分片报文 | 总字节数 | IP报头字节数 | 数据字节数 | 16位标识 | "更多分片" | 13位片偏移 |
|---|---|---|---|---|---|---|
| 1 | 1500 | 20 | 1480 | 2026 | 1 | 0 |
| 2 | 1500 | 20 | 1480 | 2026 | 1 | 185 |
| 3 | 1500 | 20 | 1480 | 2026 | 1 | 370 |
| 4 | 80 | 20 | 60 | 2026 | 0 | 555 |
组装的过程
MAC帧协议交付给上层IP协议的数据,可能来自全国各地,这些海量的数据,可能部分是分片的,部分是不是分片的,因此IP协议需要经过特定的操作来进行区分并精准的组装。
其该部分问题主要是由以下方式解决:
- IP报头中的32位源IP地址记录了发送端的IP地址,这一字段使得接收方能够直接区分数据报的来源主机。
- IP报头中的16位标识字段,用于唯一标识同一主机在同一会话中发出的不同数据报。对于未分片的独立数据,各自的16位标识值互不相同;而对同一个原始数据经分片后产生的所有分片,它们共享相同的16位标识。因此,通过该字段可以明确判断一个数据报是否为某个分片集合中的一部分。
综合上述两个字段,IP层可通过源IP地址和16位标识唯一确定属于同一原始数据的所有分片,并将其正确聚合。聚合完成后,即可依据片偏移等字段进行数据重组,还原出完整的原始报文。
对于已经确认为一组的分片的报文来说:
- 第一个分片报文的13位片偏移一定为0。
- 最后一位的更多分片一定为0。
- 对于中间部分的顺序,则是由13位片偏移来决定其顺序,其方式主要是由当前分片的片偏移 + 当前报文的数据字节数 ÷ 8得到。
分片报文丢包的问题
分片报文丢包是IP网络中一个经典且影响显著的问题,其核心在于:IP协议本身是"尽力而为"且无连接的,它不保证分片报文的完整到达,也不负责重传丢失的分片。
当一个数据报被分片后,任何一个分片丢失,都会导致整个原始数据报在接收端重组失败,从而被丢弃。
其分片报文丢包问题十分严重,比方说原始数据报被分为 N 个分片。但只要其中任意一个分片在网络中丢失、损坏或超时,整个原始数据报就无法被接收端正确重组。即使其余 N-1 个分片全部完好到达,也会被丢弃。这造成了带宽和资源的严重浪费。
并且没有分片的重传机制,单个分片丢失,发送端感知到的是整个TCP段未得到确认,它会重传整个原始大数据报,十分浪费资源。
在此问题上小则浪费一点时间,重则导致网络拥塞。
如何缓解分片丢包问题
-
避免分片
-
核心思想:让发送端主动探测到目的主机的路径上的最小MTU,然后发送不超过该大小的数据包。
-
实现 :发送端发送DF(Don't Fragment)标志置位的数据包。如果路径中某路由器的MTU小于包大小,它会丢弃该包并回复一个
ICMP Fragmentation Needed消息。发送端据此降低包大小。 -
问题:ICMP消息可能被防火墙阻断,导致PMTUD失效(即"PMTUD黑洞")。
-
-
应用层和传输层适配
-
TCP:通过MSS(Maximum Segment Size)协商,在三次握手时确定一个不会导致IP分片的数据段大小(通常是MTU-40字节)。
-
UDP应用:应用程序应控制发送的报文大小,使其适合常见MTU(如1500字节的以太网MTU),并为IP和UDP头部留出空间。
-
-
使用不分片的现代协议
- IPv6 :在IPv6中,分片功能从路由器转移到了发送端主机。路由器不再进行分片,如果包太大则直接丢弃并返回ICMPv6 Packet Too Big消息。这简化了网络设备处理,并鼓励端到端的路径MTU发现。
-
网络设备配置
- 确保防火墙和安全策略能正确处理分片报文,特别是在需要穿越防火墙的关键业务中。
跨网络传输过程中源IP地址与目标IP地址的变化
在IP数据包跨网络传输的整个端到端路径中,源IP地址和目标IP地址在IP报头中是始终保持不变的(除非经过特殊网络设备处理)。这是IP协议实现全局寻址和路由的基础。
然而,在特定网络技术(主要是NAT)的作用下,IP地址会在特定节点发生转换,但这并非IP路由本身的机制,而是一种地址复用和映射技术。
正常路由过程中的IP地址(无NAT)
| 传输阶段 | 源IP地址 | 目标IP地址 | 说明 |
|---|---|---|---|
| 发送主机 | 主机自身的IP(如 192.168.1.100) |
目标服务器的公网IP(如 203.0.113.5) |
主机构造IP数据包 |
| 经过路由器(逐跳转发) | 不变(仍是 192.168.1.100) |
不变(仍是 203.0.113.5) |
路由器根据目标IP查路由表,只修改二层地址(MAC),不修改三层IP地址 |
| 到达目标服务器 | 不变(192.168.1.100) |
不变(203.0.113.5) |
服务器看到的源IP即为发送主机的原始IP |
存在NAT(网络地址转换)时的变化
NAT设备(通常是家用或企业路由器)会修改IP地址,以实现私网地址与公网地址的映射。
及比如下面图中,如果主机A要向主机B发送数据时的情况。

-
主机A发出数据包:
-
源IP:
192.168.1.201(电脑的私网IP) -
目标IP:
122.77.241.3(公网服务器)
-
-
经过家用路由器(NAT设备):
-
路由器修改源IP ,将其替换为自己的公网IP (
10.1.1.2),并记录映射关系(WAN口IP,端口x → WAN口IP,端口x)。 -
发出的数据包变为:
-
源IP:
10.1.1.2(路由器的公网IP) -
目标IP:
122.77.241.3(不变)
-
-
-
经过运营商路由器(NAT设备):
-
路由器修改源IP ,将其替换为自己的公网IP (
122.77.241.4),并记录映射关系(WAN口IP,端口x → WAN口IP,端口x)。 -
发出的数据包变为:
-
源IP:
122.77.241.4(路由器的公网IP) -
目标IP:
122.77.241.3(不变)
-
-
-
服务器收到且回复时:
-
服务器看到的数据包:
-
源IP:
122.77.241.4(认为是客户端的地址) -
目标IP:
122.77.241.3(自己)
-
-
服务器构造回复包:
-
源IP:
122.77.241.3 -
目标IP:
122.77.241.4
-
-
-
返回经过运营商路由器(NAT设备):
-
路由器修改目标IP ,将其替换为自己的公网IP (
122.77.241.4)。 -
发出的数据包变为:
-
源IP:
122.77.241.4(路由器的公网IP) -
目标IP:10.1.1.3
-
-
-
返回经过家用路由器(NAT设备):
-
路由器修改源IP ,将其替换为自己的公网IP (
10.1.1.3),并记录映射关系(WAN口IP,端口x → WAN口IP,端口x)。 -
发出的数据包变为:
-
源IP:
10.1.1.3(路由器的公网IP) -
目标IP:192.168.1.200
-
-
-
最终主机B收到数据包
在这个过程中还是略微复杂的。但这个也是十分重要的NAT技术。
其做到了让多台设备共享一个公网IP地址上网,从而极大缓解了IPv4地址枯竭问题,并附带增强了内部网络的安全性。