--- tags: [计算机网络, 数据封装, 网络分层] create time: 2026-05-17 22:20 --- # 数据封装与解封装 ## 概述 数据在发送端逐层加上头部(Header),就像装快递盒子:最里层是商品,外面一层一层套纸箱、贴面单、打托盘。到达接收端后,每一层剥掉自己的那层包装,只把原始内容交给上层处理。这个"套娃+拆箱"的过程就是 **封装(Encapsulation)** 和 **解封装(Decapsulation)**。 > [!QUESTION] 为什么每层都要加头? > 因为每层需要知道如何管理自己的事务——传输层关心连接状态,网络层关心路由寻址,链路层关心物理介质。这些元信息必须跟在数据前面,让每一层都能正确解读并转发。 ## 数据包尺寸变化轨迹 以发送一个 HTTP GET 请求为例,追踪尺寸变化: | 层级 | 操作 | 数据结构 | 新增首部大小 | 累计大小 | |------|------|---------|-------------|---------| | 应用层 | HTTP GET 报文 | `GET / HTTP/1.1\r\nHost: example.com\r\n\r\n` | — | ~40 bytes | | 传输层 (TCP) | + TCP Header | Segment | 20 bytes | ~60 bytes | | 网络层 (IP) | + IP Header | Packet | 20 bytes (IPv4) | ~80 bytes | | 链路层 (Ethernet) | + Eth Header + FCS | Frame | 14 + 4 = 18 bytes | ~98 bytes | ```mermaid flowchart LR H["HTTP GET 40B"] --> T["+ TCP Header 20B
Segment 60B"] T --> I["+ IP Header 20B
Packet 80B"] I --> E["+ Ethernet HDR 14B + FCS 4B
Frame 98B"] E --> B["98 个 Bit 在网线上传输"] style H fill:#DDA0DD style T fill:#FFD700 style I fill:#87CEEB style E fill:#98FB98 ``` ## 发送端:逐层封装 ```mermaid sequenceDiagram participant App as HTTP 应用 participant TCP as TCP Socket participant IP as 网络层 IP participant ETH as 以太网驱动 App->>TCP: write("GET / HTTP/1.1...") Note over TCP: 分配 seq/ack, state=ESTABLISHED TCP->>IP: 传递 Segment (daddr=x.x.x.x, sport=1234, dport=80) Note over IP: 查路由表 → 下一跳网关 IP->>ETH: 传递 Packet (dst_mac=?, src_ip=192.168.1.100, dst_ip=93.184.216.34) Note over ETH: ARP 解析 → dst_mac=aabb.ccdd.eeff ETH->>ETH: 拼接 源MAC+目的MAC+EtherType+Payload+FCS ETH-->>App: sendto() 返回 → 帧已发出 ✅ ``` ### Ethernet II 帧完整结构 ``` Offset Size Field 说明 ────── ──── ───────────────── ───────────────────────────── 0 6 Dest MAC Address 目标 MAC 地址 6 6 Source MAC Address 源 MAC 地址 12 2 EtherType 0x0800=IPv4 / 0x86DD=IPv6 / 0x0806=ARP 14 N Payload IP 包(最大 1500 字节) 14+N 4 FCS CRC-32 帧校验序列(接收端自动验证) ``` 总长度范围:**64 ~ 1518 bytes**(不含 VLAN Tag;有 VLAN Tag 则上限 1522)。 > [!note] MTU = 1500 是什么意思? > MTU(Maximum Transmission Unit)是链路层允许的最大 Payload 大小,即 IP 包的最大体积。超过会被分片(Fragmentation),但分片会降低性能且增加丢包风险——这也是现代应用层(如 TLS、gRPC)倾向于小包传输的原因。 ## 接收端:逐层解封装 ```mermaid sequenceDiagram participant ETH as 网卡收到 Frame participant IP as 剥离以太网头 participant TCP as 剥离 TCP 头 participant App as 提取 HTTP 数据 ETH->>IP: 校验 FCS OK → 取 EtherType=0x0800 → 剥离以太网头 IP->>TCP: 校验 IP Checksum → 取 Protocol=6(TCP) → 剥离 IP 头 TCP->>App: 按 Sequence Number 重组 → 剥离 TCP 头 App->>App: 解析 "GET / HTTP/1.1..." 🎉 ``` 每层的动作可以概括为三步: 1. **检查**:校验和是否正确?mac/ip/port 是否指向自己? 2. **剥离**:去掉本层的 Header(必要时 Tail 如 FCS) 3. **移交**:将剩余的 Payload 交给上层协议处理 ## 各层 PDU 对照表 | OSI 名称 | PDU | TCP/IP 对应 | 关键标识字段 | |----------|-----|-------------|-------------| | 数据 (Data) | 报文段 | 应用层消息 | — | | 段 (Segment) | TCP Segment | 传输层 PDU | 源端口 + 目的端口 | | 包 (Packet) | IP Datagram | 网络层 PDU | 源 IP + 目的 IP + Protocol | | 帧 (Frame) | Ethernet Frame | 链路层 PDU | 源 MAC + 目的 MAC + EtherType | | 比特流 (Bits) | Bitstream | 物理层信号 | 电信号 / 光脉冲 | ## NAT 场景下的封装变化 NAT 路由器修改了中间层的地址: ``` 发送端内部主机 NAT 路由器 外部 Web 服务器 ┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐ │ Src IP: 10.0.0.5:45678 │ │ SNAT: 改写 Src IP │ │ Dst IP: 203.0.113.1:80 │ │ Dst IP: 203.0.113.1:80 │ → │ │ → │ │ │ │ │ → Src IP: 8.8.8.8:45678 │ │ ← Src IP: 203.0.113.1:80 │ │ │ │ → Dst IP: 203.0.113.1:80 │ │ → Src IP: 10.0.0.5:45678 │ └──────────────────────┘ └──────────────────────┘ └──────────────────────┘ ``` 注意:NAT 不触碰应用层载荷,只是在中途修改了 IP 和 TCP 端口。这也意味着 **传输层的 Checksum 需要重新计算**。 ## 关联笔记 - [[hhs/NETWORK/OSI与TCP-IP模型对比]] — 分层模型的起源与对比 - [[hhs/NETWORK/IPv4协议详解]] — IP 包的详细格式 - [[hhs/NETWORK/TCP状态机详解]] — TCP 段的结构与状态管理