我第一次装 Wireshark 的时候,对着满屏十六进制发呆,根本不知道从哪看起。后来随手点开一个包,中间栏突然变成一棵整齐的树:Frame、Ethernet II、Internet Protocol、Transmission Control Protocol……一层套一层。那棵树基本就是本章的全部内容:网络为什么分层、每层管什么、一个包怎么被层层包起来。搞懂它,后面九章的任何抓包截图你都不会害怕。
随便挑一个还支持明文 HTTP 的站点(比如 http://info.cern.ch,CERN 的第一个网站,至今还在),用浏览器或 curl http://info.cern.ch 访问,同时让 Wireshark 抓包。点开那个 GET 请求,中间栏大致长这样(字段有删减,地址换成了示例网段):
Frame 5: 91 bytes on wire (728 bits), 91 bytes captured
Ethernet II, Src: 86:4b:57:xx:xx:xx, Dst: 86:4b:57:de:56:09
Internet Protocol Version 4, Src: 192.168.1.103, Dst: 188.184.21.108
Transmission Control Protocol, Src Port: 51776, Dst Port: 80, Seq: 1, Len: 37
Hypertext Transfer Protocol
GET / HTTP/1.1\r\n
Host: info.cern.ch\r\n
\r\n
从外到内依次是:以太网帧头、IP 头、TCP 头、HTTP 报文。每一层只认自己的头,HTTP 报文对 TCP 来说就是一坨不透明的字节,TCP 头对 IP 来说同样如此。
还有一个细节值得盯一眼:抓包列表里,这个 GET 前面必然还有三个小包(SYN、SYN+ACK、ACK)。它们是 TCP 在建连接(第 4 章),应用层毫不知情。分层的好处在这里已经露头了:HTTP 完全不用关心底下发生了什么。
教科书会给你背「解耦、简化设计、互操作、可演进」,四个词都对,但不如一个具体事实好懂:你从有线网换成 Wi-Fi,或者把家里的光猫从百兆换成千兆,浏览器一行代码都不用改。物理介质天翻地覆,应用层无感,这就是分层买来的东西。
反过来也成立。HTTP/3 把底层传输从 TCP 换成了基于 UDP 的 QUIC,应用层只需要在 URL 里写 https://,几乎察觉不到。网络的每一层都被替换过至少一次,而其他层照常运转,靠的就是层与层之间只通过稳定的服务接口说话。
分层的代价也得说清楚:每层都要加自己的头。以太网一帧的负载上限(MTU)是 1500 字节,扣掉 IP 头 20 字节、TCP 头至少 20 字节,你的 HTTP 数据实际只能装 1460 字节,外层还有 18 字节的帧头帧尾。开销约 4%,不痛,但这是白交的税;高性能场景(内核旁路、RDMA)确实会想办法绕开层层拷贝。
两套模型对应关系一张表看完:
| 层 | OSI(7 层) | TCP/IP(4 层) | 常见协议/设备 |
|---|---|---|---|
| 7 | 应用层 | 应用层 | HTTP、DNS、SMTP、DHCP |
| 6 | 表示层 | (并入应用层) | 加密、编码、压缩 |
| 5 | 会话层 | (并入应用层) | 会话建立与管理 |
| 4 | 传输层 | 传输层 | TCP、UDP |
| 3 | 网络层 | 网络层 | IP、ICMP、路由器 |
| 2 | 数据链路层 | 网络接口层 | 以太网、MAC、交换机 |
| 1 | 物理层 | 网络接口层 | 网线、光纤、集线器 |
OSI 是 ISO 先画好模型再去补协议的理想国;TCP/IP 是协议先跑起来、事后归纳的四层现实。现实里 5、6、7 三层几乎从不单独实现,所以教材(包括本讲义)常按五层讲:把网络接口层拆回链路层和物理层,讲起来清楚。
考试要你默写七层你就默写七层,但自己脑子里建议只留五层,少一层是一层。
三个词各管一件事:
层与层之间是垂直调用,对等层之间是水平对话。1.1 节抓包里那个证据再提一次:你的 TCP 发出 SYN,对端的 TCP 回 SYN+ACK,中间经过的路由器对这两个包里的 TCP 字段一无所知,它只读 IP 头。数据物理上要穿过中间所有设备,逻辑上却只有两端的 TCP 在互相理解,这就是对等层通信。
发送方向下走,每层加自己的头(链路层还加尾巴),叫封装;接收方向上走,逐层剥掉,叫解封装:
应用层: [ HTTP 数据 1460 字节 ]
传输层: [ TCP 头 20 | HTTP 数据 ] ← 段 segment
网络层: [ IP 头 20 | TCP 头 | HTTP 数据 ] ← 包 packet
链路层: [ 帧头 14 | IP 包 ... | FCS 4 ] ← 帧 frame
物理层: 0101101001...(比特流) ← 比特 bit
两件事容易被忽略。其一,每层的头只有对等层会读,所以 Wireshark 才能按「以太网头说类型是 0x0800,所以往里是 IP;IP 头说协议号是 6,所以往里是 TCP」这样逐层剥开。其二,下层的负载对下层完全不透明,路由器转发时只看 IP 头,里面的 TCP 序号、HTTP 路径跟它无关。