Files
cs-note/hhs/NETWORK/01-基础概念/02-数据封装与解封装.md
T
2026-05-24 11:42:38 +08:00

127 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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<br/>Segment 60B"]
T --> I["+ IP Header 20B<br/>Packet 80B"]
I --> E["+ Ethernet HDR 14B + FCS 4B<br/>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 段的结构与状态管理