第 1 章 · 网络概述与分层

我第一次装 Wireshark 的时候,对着满屏十六进制发呆,根本不知道从哪看起。后来随手点开一个包,中间栏突然变成一棵整齐的树:Frame、Ethernet II、Internet Protocol、Transmission Control Protocol……一层套一层。那棵树基本就是本章的全部内容:网络为什么分层、每层管什么、一个包怎么被层层包起来。搞懂它,后面九章的任何抓包截图你都不会害怕。

1.1 先抓一个包

随便挑一个还支持明文 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 完全不用关心底下发生了什么。

1.2 为什么非要分层

教科书会给你背「解耦、简化设计、互操作、可演进」,四个词都对,但不如一个具体事实好懂:你从有线网换成 Wi-Fi,或者把家里的光猫从百兆换成千兆,浏览器一行代码都不用改。物理介质天翻地覆,应用层无感,这就是分层买来的东西。

反过来也成立。HTTP/3 把底层传输从 TCP 换成了基于 UDP 的 QUIC,应用层只需要在 URL 里写 https://,几乎察觉不到。网络的每一层都被替换过至少一次,而其他层照常运转,靠的就是层与层之间只通过稳定的服务接口说话。

分层的代价也得说清楚:每层都要加自己的头。以太网一帧的负载上限(MTU)是 1500 字节,扣掉 IP 头 20 字节、TCP 头至少 20 字节,你的 HTTP 数据实际只能装 1460 字节,外层还有 18 字节的帧头帧尾。开销约 4%,不痛,但这是白交的税;高性能场景(内核旁路、RDMA)确实会想办法绕开层层拷贝。

1.3 OSI 七层和 TCP/IP 四层

两套模型对应关系一张表看完:

层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.4 服务、接口、协议

三个词各管一件事:

  • 服务(service):本层能替上层做什么。比如传输层承诺「可靠的字节流」(第 3 章)。
  • 接口(interface):上层怎么调用这个服务。应用拿到网络能力的入口就是 socket(第 9 章),它就是应用层到传输层的接口。
  • 协议(protocol):同一层的两端怎么对话。TCP 规定报文格式和握手流程,HTTP 规定请求长什么样,都只约束对等双方。

层与层之间是垂直调用,对等层之间是水平对话。1.1 节抓包里那个证据再提一次:你的 TCP 发出 SYN,对端的 TCP 回 SYN+ACK,中间经过的路由器对这两个包里的 TCP 字段一无所知,它只读 IP 头。数据物理上要穿过中间所有设备,逻辑上却只有两端的 TCP 在互相理解,这就是对等层通信。

1.5 封装:每个包都是套娃

发送方向下走,每层加自己的头(链路层还加尾巴),叫封装;接收方向上走,逐层剥掉,叫解封装:

应用层:      [ 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 路径跟它无关。

练习

  1. 手算:一段 1460 字节的 HTTP 数据,装进以太网帧后总长多少字节?各层头部开销占百分之几?(提示:帧 = 14 头 + 1500 负载 + 4 帧尾)
  2. 思考:路由器转发一个包时要读哪些层的头?它读得到 HTTP 报文吗?什么设备才读得到?
  3. 动手:装个 Wireshark,抓一次对任意 https 站点的访问,对照 1.1 节的树,看看多出来的 TLS 层(第 8 章)出现在哪。