---
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 段的结构与状态管理