扩展—IP 分片与组装 一、前言以太网链路存在MTU最大传输单元 1500 字节限制当 IP 报文总长度超过 MTU 时网络层必须执行分片分片抵达目标主机后IP 层再完成组装还原完整报文。本文将基于计网知识结合报文头部字段、分层示意图、数值实例、简易代码完整梳理分片与组装逻辑。分层处理流程发送端网络层 IP 模块对超大报文分片各分片独立封装链路层帧传输接收端 IP 层收集分片重组完整报文后向上交付 TCP整套分片 / 组装逻辑对传输层完全透明TCP 感知不到底层分片行为。二、分片字段分片、重组逻辑依托 IP 首部3 个关键字段实现先明确各字段定义与作用规则2.1 标识 Identification主机每发送一份完整 IP 报文分配唯一 ID同一原始报文拆分出的所有分片标识 ID 完全一致。接收端依靠此字段区分哪些分片属于同一个原始数据包。2.2 标志 FlagsDF 位DF1禁止分片报文长度超 MTU 时直接丢弃同时返回 ICMP 差错报文 DF0允许分片。MF 位MF1当前分片后方仍存在其他分片 MF0当前分片是整个报文最后一片重组终止标记。2.3 片偏移 Fragment Offset标记分片数据在原始报文数据区的起始位置计量单位为 8 字节。实际字节偏移 偏移字段数值 × 8硬性约束除最后一片分片外其余所有分片的数据载荷长度必须是 8 的整数倍保证数据拼接无断层。三、发送端IP 分片3.1 触发条件IP 报文整体总长度 当前链路 MTU触发 IP 分片。 MTU 定义数据链路层 MAC 帧能够承载的 IP 报文最大总长度。3.2 四步流程校验长度阈值用 MTU 减去固定 20 字节 IP 头部得到单分片最大可承载数据长度1500-201480字节1480 刚好是 8 的整数倍满足片偏移对齐约束。分割原始数据报将原始 IP 数据部分切割为多段前几段固定填充 1480 字节数据最后一段装载剩余不足 1480 字节的数据。填充 IP 头部每一个分片都会复制一份完整 IP 头部差异化设置关键字段标识 ID 和原始报文保持完全一致根据分片先后顺序配置 MF 标志、片偏移数值更新当前分片自身的总长度字段。发送分片各个分片单独寻址、独立转发分片传输路径可以互不相同到达接收端时可能出现乱序。四、接收端IP 组装分片到达目标主机后由本地 IP 层执行重组操作整个过程对上层 TCP/UDP 完全透明。4.1 四步流程分片分组匹配以「标识 ID 源 IP 目的 IP 上层协议」作为分组标识将属于同一原始报文的分片存入同一个缓冲区队列。排序分片分片乱序到达是常态依靠片偏移字段从小到大完成排序确定每一段数据的拼接位置。校验分片接收两个条件同时满足判定分片齐全 ① 缓冲区队列内存在 MF0 的末尾分片 ② 末尾分片的结束字节 片偏移 ×8 当前分片数据长度 原始报文总数据载荷长度。传递上层协议按照偏移顺序拷贝所有分片数据保留第一个分片的 IP 头部清除分片标记、更新总长度、重算校验和丢弃其余分片多余 IP 头部组装完成后交付传输层 TCP。4.2 核心疑问如何判断收到的报文经过分片读取标志位与偏移字段只要 MF1或片偏移数值 0即可判定该报文是分片。如何确认所有分片全部接收完毕成功收到 MF0 的末尾分片且所有分片拼接后的数据总长与原始载荷匹配才算收齐若超时未集齐全部分片主机直接丢弃当前已接收的所有分片不会向上交付残缺数据。分片如何组合还原完整报文内存开辟一块缓冲区按片偏移升序依次将各分片数据拷贝到对应字节位置拼接完成后重构标准 IP 头部。五、组装代码参考 Linux 协议栈分片重组核心逻辑简化内核复杂结构适配本科学习理解// IP分片重组入口函数 struct iphdr* ip_reassemble(struct fragment_queue *queue) { // 1. 判断是否集齐所有分片队列中存在MF0的末尾分片 if (!queue-has_last_frag) return NULL; // 2. 开辟缓冲区存放完整原始数据载荷 char *full_data malloc(queue-total_data_len); // 3. 按片偏移升序遍历分片队列依次拷贝分片数据 struct frag_node *cur queue-head; while(cur ! NULL) { int byte_offset cur-offset * 8; memcpy(full_data byte_offset, cur-data, cur-data_len); cur cur-next; } // 4. 复用第一个分片IP头清除分片标记、恢复原始总长 struct iphdr *full_ip_header copy_ip_header(queue-first_frag-header); full_ip_header-total_len 3000; // 原始完整报文总长 full_ip_header-flags 0; // DF0、MF0清除分片标识 full_ip_header-frag_offset 0; // 5. 拼接IP头部与完整数据载荷返回完整IP报文 concat_header_data(full_ip_header, full_data); return full_ip_header; }说明前置校验无末尾分片直接返回重组失败基于片偏移换算真实字节位置有序拷贝分段数据重构标准 IP 头部移除分片相关字段标记还原原始报文格式。六、缺点与优化6.1 IP 分片的短板分片独立传输任意一个分片丢失都会导致整份报文重组失败大幅提升丢包概率路由器分片、主机组装会额外消耗网络层 CPU 计算资源防火墙、安全网关常拦截分片报文容易引发业务通信不通。6.2 TCP 预先分段传输层 TCP 会主动拆分应用数据段控制【TCP 段数据 IP 头部】总长度≤1500 字节从源头规避 IP 分片降低丢包风险是网络开发标准最优方案。