§ 2.3 · Section

分层实战

Protocols in Their Layers

前面学了 OSI 七层、TCP/IP 四层,也学了 HTTP、TCP、UDP、IP 这些协议。这一篇把它们"对号入座"——每个协议到底在哪一层?为什么在这一层?理解了"谁在哪层",你就能像医生看 X 光片一样,一眼看穿网络问题的病根。

生活场景
🚗 车坏了,修理工怎么找问题

你车坏了,开去修理厂。修理工不会瞎拆——他先问:"是发动机问题、变速箱问题、还是电路问题?"
发动机 → 打开发动机盖修
变速箱 → 钻车底修
电路 → 查保险丝修
网络也一样——先判断"问题出在哪一层",再拆那一层的"盖子"修。分层模型就是网络的"修理手册"。

协议对号入座总表

协议OSI 层TCP/IP 层一句话记住
HTTP / HTTPS7 应用层4 应用层浏览器和服务器聊天
FTP7 应用层4 应用层传文件
SMTP7 应用层4 应用层发邮件
POP3 / IMAP7 应用层4 应用层收邮件
DNS7 应用层4 应用层域名翻译成 IP
SSH7 应用层4 应用层远程登录
SSL / TLS6 表示层4 应用层加密解密
TCP4 传输层3 传输层可靠传输
UDP4 传输层3 传输层快速传输
IP3 网络层2 网络层寻址和路由
ICMP3 网络层2 网络层网络诊断(ping)
IGMP3 网络层2 网络层组播管理
Ethernet2 数据链路层1 网络接口层有线局域网
WiFi (802.11)2 数据链路层1 网络接口层无线局域网
ARP2 数据链路层1 网络接口层IP 找 MAC
PPP2 数据链路层1 网络接口层拨号上网

这张表可以当厨房的归位图来看:刀在案板上、锅在灶上、菜在冰箱里,每样东西都有固定位置。背协议名意义不大,但知道"这个协议住在哪一层"极其有用——因为排障时你第一件要做的事,就是判断病灶在哪一层。说白了,这张表就是网络世界的科室分布图。

判断"某个协议在哪一层"的三条准则

上面那张表可以直接背,但更有用的是学会自己判断。遇到一个陌生协议时,问自己三个问题就够了:

这三个问题打个比方就是看一个人是哪个部门的三种办法:看他跟谁打交道(用什么地址找人)、看他的工位安在哪个办公室里(被封在谁里面)、看他每天干的活儿服务谁(服务对象是谁)。三条问下来,八成的陌生协议都能归对位。

拿几个"位置尴尬"的协议练一练,你会发现这三条准则能把争议说清楚:

协议用什么地址封在谁里结论
ARP输入 IP,输出 MAC,跨两层直接封在以太网帧(EtherType 0x0806)多数教材归二层,因为它不经过 IP
ICMPIP 地址封在 IP 包里(协议号 1)三层——它是 IP 的配套报错机制
OSPF / BGPIP 地址OSPF 直接在 IP 里(89);BGP 跑在 TCP 179 上功能上都是三层(路由计算),但 BGP 的封装在四层之上
DHCP启动时还没有 IP,靠广播封在 UDP(67/68)里七层(应用层协议),但干的是配三层地址的活
TLS无自己的地址封在 TCP 载荷里,又承载 HTTP争议:OSI 视角属表示层,工程上常称 4.5 层
VXLAN外层 IP + 内层 MAC把整个二层帧封进 UDP 4789跨层封装——用三/四层承载二层

最后一行的 VXLAN 提示了一个重要事实:"某协议在第几层"这个问题,在遇到隧道技术时会失去唯一答案。因为隧道的本质就是"把一个完整的低层数据包当成高层的载荷来运",层次关系被折叠成了嵌套关系。这一节的后半部分会专门讲这件事。

那句"遇到隧道就失去唯一答案"值得解释一下。隧道说白了就是"把一整个已经打包好的箱子,当成货物再塞进另一个箱子里寄走"——这时候你问"这箱货算第几层",就跟问"这个套娃是第几个"一样:取决于你从外往里数到第几层。层次关系被折叠成了嵌套关系,线性的编号就不够用了。

排查问题 · 从哪层开始

网络出问题了,怎么快速定位?分层模型给你一张"排查地图":

这套顺序说白了就是医院的分诊流程:不管病人说得多含糊,护士都按固定顺序一路问下来——量体温、测血压、问哪儿疼,一步步把范围缩到某个科室。网络排障也一样,"网断了"这三个字毫无信息量,但"能 ping 通 IP、打不开网页"就已经把病灶锁定到 DNS 这一个器官上了。

第 1 步 · 物理层检查

网线插了吗?WiFi 连了吗?路由器灯亮吗?—— 90% 的问题在这一步解决。

第 2 步 · 数据链路层检查

电脑和路由器通了吗?ping 192.168.1.1 通吗?—— 不通说明本地连接有问题。

第 3 步 · 网络层检查

能 ping 通外网 IP 吗?ping 114.114.114.114—— 不通说明路由或 ISP 有问题。

第 4 步 · 传输层检查

特定端口通吗?telnet baidu.com 80—— 不通说明防火墙拦了。

第 5 步 · 应用层检查

网页能打开但慢?视频能看但卡?—— 应用层或服务器问题。

Analogy · 看病

你去医院,医生不会一上来就做全身 CT——先问"哪不舒服?"(定位),再查对应科室(分层)。
网络排查也一样——先定位"哪层不舒服",再查那一层的"专科"

一次网页访问的"全层之旅"

把你前面学的所有知识串起来——你输入 baidu.com 按回车,数据在各层之间这样流动:

先用一句大白话概括这趟旅程:你敲的那句话,先被裹上四层包装扔出门,中途被十几个中转站看了看外皮,到了对面再被一层层拆开,最后原封不动地摆在服务器面前。下面这七步,说的就是"包装、上路、拆包"这三件事。

应用层(第 4 层)

浏览器构造 HTTP 请求:"GET / HTTP/1.1 Host: baidu.com"。

传输层(第 3 层)

HTTP 数据被 TCP 分段,加序号,准备可靠传输。

网络层(第 2 层)

DNS 先把 baidu.com 翻译成 IP(比如 110.242.68.66),然后 IP 协议加上源 IP 和目标 IP。

网络接口层(第 1 层)

Ethernet/WiFi 加上 MAC 头,变成电信号/无线电波发出去。

穿越互联网

经过你家路由器(NAT 转换)、运营商骨干、百度机房路由器——每一跳都"看"IP 头决定下一跳。

百度服务器接收

反过来一层层剥皮:接口层 → 网络层 → 传输层 → 应用层,最后看到 HTTP 请求。

返回数据

百度服务器把网页内容按同样路径发回来——你屏幕显示出网页。

把"全层之旅"拆到字节级

上面那个流程是"故事版",现在换"工程版"。我们把一次 https://example.com/ 的访问从按下回车开始,逐个动作列出来,并标明每一步动了哪一层:

换句话说,上面那段是"故事版",下面这段是厨房里的实际操作单——精确到"第几步、动了哪口锅、加了多少克盐"。这份操作单值得慢慢读,因为它把前面所有抽象概念第一次串成了一条真实的时间线。

【第 0 步·七层】浏览器解析 URL
  scheme=https  host=example.com  port=443(默认)  path=/

【第 1 步·七层】查本地缓存 → 查 hosts 文件 → 发 DNS 查询
  DNS 报文(约 29 字节)→ 封进 UDP(8B)→ IP(20B)→ 以太网(14B)
  目的端口 53,目的 IP = 系统配的 DNS 服务器(如 192.168.1.1)
  ↩ 收到应答:example.com = 93.184.216.34

【第 2 步·二层】本机还不知道网关的 MAC → 发 ARP 广播
  "谁是 192.168.1.1?" → 网关回:"a4:2b:b0:c1:d2:e3"
  写入 ARP 缓存(注意:这一步跳过了三层和四层)

【第 3 步·四层】TCP 三次握手(三个包,各 0 字节数据)
  → SYN     seq=1000, win=64240, MSS=1460, SACK_PERM
  ← SYN+ACK seq=8000, ack=1001, win=65535
  → ACK     seq=1001, ack=8001
  此时内核里生成了一个五元组条目:
  (TCP, 192.168.1.20:54321, 93.184.216.34:443)

【第 4 步·表示层/4.5 层】TLS 1.3 握手(1 个 RTT)
  → ClientHello   带 SNI=example.com(明文!)、支持的密码套件、密钥份额
  ← ServerHello + 证书 + Finished
  → Finished      此后所有内容被 AES-GCM 加密

【第 5 步·七层】终于发出真正的 HTTP 请求
  明文内容(约 120 字节):
    GET / HTTP/1.1\r\nHost: example.com\r\nUser-Agent: ...\r\n\r\n
  → 被 TLS 加密成一条 TLS 记录(+5 字节记录头 +16 字节认证标签)
  → 被 TCP 封装(+20 字节,seq=1001)
  → 被 IP 封装(+20 字节,TTL=64,协议号 6)
  → 被以太网封装(+14 字节,目的 MAC = 网关的 MAC)
  → 网卡编码成电信号发出

【第 6 步】中间十几跳的转发(下一节详述谁看哪层)

【第 7 步·反向解封装】服务器收到
  剥以太网 → 剥 IP → 交给 TCP → 排序并 ACK → 交给 TLS 解密 → 交给 HTTP
  服务器返回 200 OK + HTML

【第 8 步·七层】浏览器渲染,并为页面里的 CSS/JS/图片
  复用同一条 TCP 连接(keep-alive)或另开几条并行连接

这个流程里有三个细节特别值得注意。第一,DNS 查询发生在建立 TCP 连接之前——它自己就是一次完整的四层通信(UDP 53),走完了从应用层到物理层的全程,然后才轮到主请求。所以"打开一个网页"至少包含两次独立的网络往返。

换成大白话:DNS 查询本身就是一次完整的往返——相当于你出门前先打个电话问清地址,这通电话跟后面那趟送货是两件独立的事。所以"打开一个网页"从来不止一次通信,起码是"先问路、再上门"两趟。

第二,ARP 请求完全跳过了三层和四层。它的报文直接封在以太网帧里,EtherType 是 0x0806,里面没有 IP 头也没有端口。这是"分层不是铁板一块"的第一个例证——链路层需要向上问一个三层的问题(这个 IP 对应哪个 MAC),于是就出现了一个横跨两层的协议。

ARP 为什么"跳层"?说白了就是:楼下的收发室知道要送到"5 号楼 301",但他手上只有一本"哪个门牌对应哪扇门"的册子——册子上没有的,他就得在院子里喊一嗓子问。这一嗓子既用到了上层的信息(IP),又完全走的下层的路(直接封在以太网帧里),所以它横跨了两层。分层从来不是铁板一块。

第三,真正的业务数据(那 120 字节的 HTTP 请求)是最后才出场的。在它之前,网络上已经跑了 DNS 两个包、ARP 两个包、TCP 握手三个包、TLS 握手三四个包——大约十个包、三到四个 RTT,一个字节的网页内容都还没开始传。这就是为什么"减少往返次数"(HTTP/2 多路复用、TLS 1.3、QUIC 的 0-RTT、DNS 预解析)是 Web 性能优化的第一大主题。

这一条最值得记牢,用生活话讲就是:你走进餐厅,还没点菜,前面已经发生了一堆事——问路、找座、对服务员确认"这儿能坐吗"、看菜单、报手机号会员登记……十来个回合下来一口菜都还没上桌。三到四个 RTT 在跨国链路上就是半秒多,全花在"你好你好"上了。所以 Web 优化的头号主题从来不是"传得更快",而是"少寒暄几轮"。

各层各加了多少字节:一笔完整的开销账

把封装的字节数摊开算,能让你对"协议开销"有量化的直觉。以一次典型的 HTTPS 传输为例:

这笔账打个比方就是称一下"礼物"和"最终那个包裹"分别多重:礼物本身一斤半,包好以后一斤六两——纸箱、气泡膜、面单加起来占了一两。寄冰箱时这点包装可以忽略,寄一支口红时包装就比货重了。

加了什么字节数关键字段
七层 HTTP请求行 + 头部200 ~ 800(含 Cookie 时可能上千)Host、Cookie、User-Agent
TLS 记录记录头 + AEAD 认证标签5 + 16 = 21类型、版本、长度
四层 TCPTCP 头(含时间戳等选项时更长)20 ~ 60端口、序号、ACK、窗口、标志位
三层 IPv4IP 头20(IPv6 固定 40)源/目的 IP、TTL、协议号
二层以太网帧头 + FCS14 + 4 = 18目的/源 MAC、EtherType
一层物理前导码 + SFD + 帧间隙8 + 12 = 20(占线时不占帧)时钟同步用

算一笔最典型的账:一个满载的 TCP 段能装 1460 字节数据(MSS = 1500 − 20 − 20)。加上各层头部后线上占用 1538 字节(1460 + 20 TCP + 20 IP + 18 以太网 + 20 物理开销)。有效载荷率 = 1460 / 1538 ≈ 94.9%,也就是说约 5% 的带宽被协议头部吃掉了。如果启用了 TCP 时间戳选项(多 12 字节)、走 IPv6(多 20 字节)、或套了 VPN,这个比例还会继续下降。

94.9% 这个数字换算成生活话就是:你寄一箱 30 斤的东西,纸箱和泡沫总共一斤半——完全划得来。这就是为什么下载大文件时压根不用操心协议开销:包装占比不到二十分之一。但下面那几个小包场景,账目会立刻变得难看。

但下载文件是最好的情况。换成小包场景,账目立刻惨不忍睹:

场景 A · 下载大文件(1460 字节满载)
  有效数据 1460 / 线上 1538 = 94.9% 有效率  ✔

场景 B · 网游位置同步(每包 20 字节数据,UDP)
  20 数据 + 8 UDP + 20 IP + 18 以太 + 20 物理 = 86 字节
  有效率 = 20 / 86 = 23.3%                  ✘ 四分之三是包装

场景 C · SSH 里敲一个字符(1 字节数据,TCP)
  1 数据 + 20 TCP + 20 IP + 18 以太 + 20 物理 = 79 字节
  有效率 = 1 / 79 = 1.3%                    ✘✘ 一个字符发 79 字节

场景 D · 一个纯 ACK 包(0 字节数据)
  0 + 20 + 20 + 18 + 20 = 78 字节,纯管理成本
  这就是为什么 TCP 要有"延迟确认"——攒一攒再回一个 ACK

场景 C 直接解释了 Nagle 算法为什么存在:1984 年 John Nagle 在 RFC 896 里指出,Telnet 这类交互应用每敲一个键就发一个 41 字节的包(当时头部更小),网络上 98% 都是包装,会把链路撑爆。他的方案是"手上有未确认的小包时,就先攒着,等 ACK 回来或攒够一个 MSS 再发"。分层带来的头部开销,逼出了 TCP 里一整套"攒包"的机制——而这些机制又反过来引入了延迟问题。

场景 C 那个数字值得单独念一遍:你在 SSH 里敲一个字符,网线上跑了 79 个字节——相当于寄一颗纽扣,用了一个鞋盒加半包泡沫。Nagle 算法的思路特别朴素:先攒一攒,凑够一箱再寄。就像你不会为了买一瓶酱油单独下一次外卖,而是等想买的东西凑够几样一起下单。代价是——你会稍微多等一会儿。

过路的设备各看哪一层

一个包从你家到服务器,会经过许多设备。它们并不是"都从头到尾拆一遍"——每种设备只拆到自己需要的那一层就停手,这是它们性能差异的根本原因

这件事打个比方就是快递路上遇到的各种角色:传送带只管把箱子往前送(压根不看面单);分拣员看一眼邮编就扔上传送带(只看外层);中转站要撕旧标签贴新标签(改一点点);而海关要开箱验货、逐件登记(拆到最里面)。拆得越深,能干的事越多,也越慢——这就是四层负载均衡和七层负载均衡差一个数量级的全部原因。

设备 / 中间盒拆到第几层看什么字段可能改什么典型延迟
中继器 / 光模块1 物理层只放大和整形信号不改任何内容纳秒级
交换机2 链路层目的 MAC、VLAN 标签加/去 VLAN 标签微秒级
路由器3 网络层目的 IP,查路由表TTL 减 1、重算校验和、换 MAC 头数十微秒
NAT 网关(家用路由器)4 传输层IP + 端口(要建映射表)改源 IP、改源端口、改两处校验和数十微秒
四层防火墙 / ACL4 传输层五元组 + TCP 标志位放行或丢弃,可回 RST微秒级
四层负载均衡(LVS)4 传输层目的 IP + 端口改目的 IP(DNAT)或改 MAC(DR 模式)数十微秒
七层负载均衡(Nginx)7 应用层Host、URL、Cookie、Header完全重建一条新连接,可改任何内容毫秒级
WAF / DPI 设备7 应用层整个报文内容做模式匹配拦截、告警、插标记毫秒级
CDN 边缘节点7 应用层URL、缓存键直接返回缓存,不回源取决于是否命中

这张表解释了很多工程决策。为什么四层负载均衡比七层快一个数量级?因为四层只需要改几个字段就把包扔出去,甚至可以在网卡的 ASIC 里做;七层要完整地把 TCP 流重组、解析 HTTP、决策、再建一条新连接发给后端——它实际上是两条独立的 TCP 连接,中间由一个程序搬运数据。代价换来的是能力:只有七层能实现"以 /api/ 开头的走 A 集群,带某个 Cookie 的走灰度集群"这种规则。

再用一句大白话钉一遍:四层负载均衡像门口那个只看门牌号的分拣员——瞟一眼、改个标签、扔出去,快得飞起;七层像海关——开箱、看清里面是什么、决定走哪条通道、然后重新装一个新箱子发出去。慢一个量级,但只有它能做"带某个 Cookie 的走灰度"这种精细活。

为什么 HTTPS 让七层负载均衡变复杂?因为内容被加密了,中间设备看不到 URL 和 Header。解法有两种:一是TLS 终结(把证书私钥放在负载均衡器上,它解密后再明文转给后端),二是TLS 透传(不解密,只能靠 ClientHello 里明文的 SNI 字段决定转给谁,退化成"四层 + 一点点信息")。前者性能好功能全但安全边界扩大,后者安全但只能按域名分流。

这两种解法用生活话讲就是:TLS 终结=你把家门钥匙交给了小区的代收点,让它替你开箱验货再转给你(方便,但你的钥匙多了一份在别人手上);TLS 透传=代收点不开箱,只看箱子外面写的收件人名字来决定送哪栋楼(安全,但它只知道"送给谁",不知道"里面是什么")。前者能力强、边界大,后者边界小、能力弱——没有免费的选择。

抓包实操:亲眼看到七层展开

前面全部是文字描述,现在动手看一次。Wireshark 的界面天生就是分层的——它的中间那个面板就是把一个包按层次展开的树。这是理解分层最快的方式,没有任何替代品:

抓包为什么值得动手做一次?因为它相当于把一件快递从最外层大箱到最里面那件礼物,逐层拆开摆在桌上,每一层的面单上写了什么都看得一清二楚。前面讲了半天"面单上应该有哪些栏目",抓一次包你就真看见了那些栏目里填的字。

Wireshark 展开一个 HTTPS 包,你会看到这样一棵树:

▶ Frame 42: 583 bytes on wire (4664 bits), 583 bytes captured
    ↑ 这是抓包工具自己加的元信息,不属于任何协议层

▶ Ethernet II, Src: 00:1a:2b:3c:4d:5e, Dst: a4:2b:b0:c1:d2:e3
    Type: IPv4 (0x0800)                    ← 第 2 层,14 字节

▶ Internet Protocol Version 4, Src: 192.168.1.20, Dst: 93.184.216.34
    Header Length: 20 bytes
    Time to Live: 64
    Protocol: TCP (6)                      ← 第 3 层,20 字节
    Header Checksum: 0x0000 [validation disabled]

▶ Transmission Control Protocol, Src Port: 54321, Dst Port: 443,
                                 Seq: 1, Ack: 1, Len: 517
    Flags: 0x018 (PSH, ACK)
    Window: 64240
    ▶ [SEQ/ACK analysis]                   ← 第 4 层,20 字节
    ▶ [Timestamps]

▶ Transport Layer Security
    ▶ TLSv1.3 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)          ← 兼容性伪装,实际是 1.3
        Length: 512
        ▶ Handshake Protocol: Client Hello
            ▶ Extension: server_name (len=22)
                Server Name: example.com   ← SNI 明文可见!

# 关键洞察:这棵树的每一层,就是发送方封装时加的一层壳。
# Wireshark 做的事就是照着协议规范反向剥壳。

这棵树最妙的地方在于:它的每一层,恰好就是发送方封装时套上的一层箱子。发货方一层层往外套,Wireshark 一层层往里拆,两边完全对称。顺便留意树里那个 Server Name: example.com——这一栏是明文的,也就是说箱子上锁了,但箱子外面写的收件人名字谁都看得见。

几条实用的抓包命令和过滤器,能省下大量翻页时间:

# tcpdump(服务器上没有图形界面时用)
$ tcpdump -i eth0 -nn host 93.184.216.34 and port 443 -w out.pcap
    -i 指定网卡   -nn 不解析域名和端口名(快很多)
    -w 存成文件,之后拖回本地用 Wireshark 打开
$ tcpdump -i any -nn 'tcp[tcpflags] & (tcp-syn) != 0'   # 只看 SYN 包

# Wireshark 显示过滤器(注意和抓取过滤器语法不同)
eth.addr == a4:2b:b0:c1:d2:e3     # 二层:按 MAC 过滤
ip.addr == 93.184.216.34          # 三层:按 IP 过滤
ip.ttl < 5                        # 三层:找快要过期的包
tcp.port == 443                   # 四层:按端口
tcp.flags.syn == 1 && tcp.flags.ack == 0   # 四层:只看握手第一个包
tcp.analysis.retransmission       # 四层:找出所有重传(诊断丢包神器)
http.request.method == "GET"      # 七层:只看 GET 请求
tls.handshake.extensions_server_name contains "example"  # 七层:按 SNI

# 右键任意包 → Follow → TCP Stream:把一条连接的全部往来拼成一整段
# 这是排查应用层协议问题最好用的功能

抓包时最容易犯的两个错误值得提前说。第一,在错误的位置抓包。包丢在中途时,在客户端抓只能看到"发出去没回应",在服务端抓才能确认"到底有没有收到"。两头同时抓、对比时间戳是定位丢包位置的标准手法。第二,忘了 HTTPS 抓不到明文。要看加密内容必须在浏览器里设 SSLKEYLOGFILE 环境变量导出会话密钥再喂给 Wireshark,否则你只能看到 TLS 层为止。

第一个错误值得再说一遍,因为它太常见了:包丢在中途时,只在自己这头抓包,你永远只能看到"我发出去了、没人回我"——压根判断不了到底是"没送到"还是"送到了但对方没回"。正确做法是两头同时抓、对比时间戳,就像丢件时既要查发货记录、也要查收货记录,只看一头永远说不清。

分层的代价:性能开销从哪来

分层不是免费的午餐。除了前面算过的头部字节开销,还有三笔隐性成本,在高性能场景下会成为瓶颈:

这三笔隐性成本用厨房里的重复劳动来理解最顺:把菜从案板挪到盘子、盘子挪到锅里、锅里挪到碗里(内存拷贝);每来一个客人就跑去门口应一次门(中断);同一份菜称了三遍重(重复校验)。平时这点浪费无所谓,但一晚上要出两千份菜时,光这三件事就能把厨师累垮。

值得注意的是,这些优化手段本质上都在部分打破分层。TSO/GSO(TCP 分段卸载)让网卡代替内核做 TCP 分段,等于把四层的活交给了硬件;LRO/GRO 在收包时把多个小包合并成一个大包再交给上层,等于让二层理解了四层的语义。分层是为了让人类能理解和维护系统,而当机器性能成为瓶颈时,人们会毫不犹豫地在实现层面把这些边界"焊接"起来——但对外仍然假装它们是分开的。

这段结论说白了就是:分层是给人看的,性能是给机器用的。纸面上大家还是各司其职,实际上工程师早就在几个交界处偷偷把墙打通了——让网卡替内核切包、让二层看懂四层的语义。好比一家小厨房,菜单上写着"切配、炒锅、摆盘"三道工序,实际上都是同一个人一手完成的——分工是写给客人看的,效率是自己的事。

分层被打破的四种真实情况

教科书告诉你"每层只跟相邻层打交道"。现实中这条规则被打破得相当频繁,而且每一次打破都有充分的商业理由。认清这些"违规者",是从"懂模型"走向"懂现实"的关键一步。

换成大白话就是:教科书说"各管一段、不许越界",可现实里越界的事天天在发生——而且每一次越界都是被逼出来的,都有它的道理。背会规则只算入门,知道规则在哪儿被破、为什么破,才算真懂。

违规者一:NAT——三层设备偷看四层。一个纯正的路由器不该关心端口号,但 NAT 必须改端口,否则无法区分内网里的多台机器。它维护一张映射表:

家用路由器里的 NAT 映射表(简化):

内网侧                        外网侧                       目标
192.168.1.20:54321   ←→   203.0.113.5:61001   →   93.184.216.34:443
192.168.1.21:54321   ←→   203.0.113.5:61002   →   93.184.216.34:443
        ↑ 两台机器凑巧用了同一个源端口
          NAT 靠"换一个外网端口"把它们区分开

# 后果一:NAT 必须同时改 IP 头(源 IP)和 TCP 头(源端口),
#         并重算两个校验和 —— 明确跨了三层和四层
# 后果二:外网无法主动连内网(映射表里没有条目),
#         这打破了 IP 的"任意两台主机可直接通信"假设
# 后果三:映射表有超时(TCP 常见几分钟到几小时),
#         长时间不发数据的连接会被静默丢弃 —— 这就是
#         为什么长连接应用必须发心跳包

NAT 为什么算"违规"?因为一个本该只看地址的分拣员,非要拆开看里面的房间号——不看不行,因为整栋楼共用一个门牌,不看房间号他分不清是哪一户的货。而那个"映射表会超时"的后果特别实用:代收点的登记本几分钟就清一次,你太久不来取,条目一删,外面的货就再也送不进来了——这就是所有长连接应用必须定时发心跳的原因。

违规者二:DPI——网络中间设备读应用层内容。深度包检测让运营商和企业防火墙能看到你在用什么应用、访问什么网站,用于限速、计费、审计、封锁。它把整个包从二层拆到七层,做正则匹配或机器学习分类。这是对端到端原则最彻底的违背,也是 HTTPS 全面普及和 QUIC 加密一切的直接动因——加密是端点对中间盒的一种反制

DPI 说白了就是中转站开箱验货:本来它只该看面单,现在它把箱子拆到底、逐字翻看,用来限速、计费、审计、封锁。而 HTTPS 和 QUIC 全面加密,本质上就是收发双方的反击:既然你要拆,那我给箱子上锁。这场"拆锁之争"是近十年互联网协议演进最大的一条暗线。

违规者三:TLS 中间盒与 TLS 终结。企业网关为了做内容审计,会在员工电脑上装一张自签根证书,然后合法地对所有 HTTPS 做中间人攻击:它和你建一条 TLS,再和真服务器建另一条,中间明文过一遍。CDN 和负载均衡器也是同样机制。这打破了"只有两个端点能看到明文"的承诺,代价是整条链路的安全性取决于最弱的那个中间盒。

TLS 中间盒这件事,通俗地说就是:公司在你的电脑里预先塞了一把"万能钥匙的备份",于是它可以合法地把每一个箱子拆开看一遍,再重新装好递给你——而你的浏览器全程不报警,因为那把钥匙是"被授权"的。代价是:整条链路的安全,取决于那个中间盒有多靠得住。

违规者四:跨层优化。无线网络里有一类经典问题:TCP 认为"丢包 = 网络拥塞 = 应该减速",但 WiFi 和 4G 的丢包大多是信号干扰造成的,此时减速完全是误判。于是出现了各种"跨层通知"方案,让链路层把"这次丢包是无线干扰不是拥塞"的信息告诉传输层。ECN(显式拥塞通知,RFC 3168)也是类似思路:让路由器在 IP 头里打一个标记,直接告诉端点"我快堵了",而不是靠丢包来暗示。

跨层通知的思路说白了就是:与其让司机靠"东西丢了"来猜"路是不是堵了",不如让路边的交警直接告诉他"我这儿快堵了,悠着点开"。丢包是一种极其低效的沟通方式——它靠"损失"来传递信息。ECN 干的活儿就是把这句话明说出来,省掉那次白丢的损失。

隧道与嵌套:分层被"折叠"起来

还有一类现象比"打破分层"更奇特:把整个协议栈套进另一个协议栈里。这叫隧道(Tunneling),它让层次关系从"线性堆叠"变成了"递归嵌套"。

隧道说白了就是套娃式寄快递:你把一个已经贴好面单、准备寄往上海的箱子,整个塞进另一个更大的箱子里,外面这个箱子写着"寄往广州某代收点"。公网上所有人只看得见外面那个箱子——真正的目的地藏在里头。VPN 干的就是这件事。

【场景一】VPN(WireGuard,UDP 51820)
  [外层以太网 14][外层 IP 20][UDP 8][WG 头 32]
      [内层 IP 20][内层 TCP 20][HTTPS 数据 ...]
   ↑ 公网只看到你在跟 VPN 服务器传 UDP
   ↑ 真正的目的 IP 藏在加密的内层里
   开销:14+20+8+32 = 74 字节,MSS 被压到 1500-74-40 = 1386

【场景二】VXLAN(数据中心二层打通,UDP 4789)
  [外层以太 14][外层 IP 20][UDP 8][VXLAN 8]
      [内层以太 14][内层 IP 20][内层 TCP 20][数据]
   ↑ 用三层网络承载完整的二层帧!
   ↑ 让两台跨机房的虚拟机以为自己在同一个交换机上
   开销 50 字节,所以 VXLAN 网络的底层 MTU 通常要设 1550+

【场景三】IPv6 over IPv4(6in4,协议号 41)
  [以太 14][IPv4 20][IPv6 40][TCP 20][数据]
   ↑ 在只支持 IPv4 的网络上传 IPv6 —— 过渡期的标准手段

【场景四】HTTP CONNECT 代理里跑 HTTPS
  [以太][IP][TCP][HTTP CONNECT 建立隧道后]
      [TLS][HTTP 请求]
   ↑ 七层协议承载了一条四层隧道,隧道里又跑七层

【场景五】层层套娃的真实惨案(远程办公常见)
  以太网 → IP → UDP → VPN → IP → TCP → TLS → HTTP → WebSocket
  → 里面又跑一个自定义二进制协议
   总头部开销可能超过 150 字节,MSS 掉到 1300 以下
   任何一层的 MTU 没配好,都会导致"小请求正常、大请求卡死"

套娃的代价可以直接换算出来:每套一层箱子,能装的货就少一点。VPN 那 74 字节的外层包装,等于把内层能装的东西从 1460 压到了 1386——相当于原本能装 730 个汉字,现在只能装 693 个。而场景五那个"层层套娃的惨案",头部开销加起来超过 150 字节,MSS 掉到 1300 以下——任何一层没配好,症状就是"小请求正常、大文件卡死"。

隧道最常见的实战故障是 MTU / MSS 不匹配,症状极具欺骗性:ping 通、小请求正常、一传大文件或大响应就卡死超时。原因是外层封装吃掉了字节,导致内层 1500 字节的包超过了路径上的实际 MTU;如果这个包还设了"不可分片"标志(DF=1,现代系统默认),路由器会直接丢弃并回一条 ICMP"需要分片"消息——而大量防火墙会把这条 ICMP 拦掉,于是发送方永远收不到通知,只是一直重传到超时。这就是著名的"PMTUD 黑洞"。

这个故障的欺骗性极强,说白了就是:你的箱子超尺寸了,中转站把它退回来了,还附了一张"太大了,最多只能过这么大"的通知单——可这张通知单被半路的门卫扣下了。于是你只知道货一直送不到,却永远不知道为什么,只能一遍遍重寄到放弃。小箱子本来就没超尺寸,所以一路顺畅——这就是"小请求正常、大文件卡死"的全部真相。

标准的解法有三种:让隧道设备做 MSS Clamping(在握手时强行把 SYN 包里宣告的 MSS 改小)、把接口 MTU 手动配小、或者让底层网络支持更大的 MTU(数据中心里给 VXLAN 底层配 9000)。排查这类问题的第一招是用指定大小的 ping 二分测试:

# Windows:-f 表示不可分片,-l 指定载荷大小
$ ping -f -l 1472 example.com     # 1472 + 8 ICMP + 20 IP = 1500,正好
   若成功 → 路径 MTU ≥ 1500
$ ping -f -l 1473 example.com
   "需要拆分数据包但是设置 DF" → 说明 1500 就是上限

# Linux:-M do 表示禁止分片,-s 指定载荷
$ ping -M do -s 1472 example.com
$ ping -M do -s 1372 example.com   # 套了 VPN 时往往只有这个能通

# 二分几次就能找到真实的路径 MTU,然后据此配置接口

那三种解法用生活话讲就是:MSS Clamping=在下单那一刻就直接跟对方说"我这边只能收小箱子,你别装那么满"(最省事,也最常用);手动配小接口 MTU=自己规定"从今往后我只用小箱子";让底层支持更大 MTU=干脆把整条线路的传送带换宽(数据中心里能这么干,公网上不行)。而排查的第一招永远是那句"用指定大小的 ping 二分试一试"——几次就能试出这条路真正的箱子尺寸上限。

常见问题定位练习

下面这张表是给入门用的"照着做"清单。用法很简单:先在左边找到你的症状,再看中间那一列该去哪个科室,最后按右边那一列做检查。说白了就是一份网络版的分诊单。

症状可能出问题的层排查方法
WiFi 连不上1 物理层 / 2 链路层检查密码、信号强度、路由器
能连 WiFi 但打不开网页3 网络层ping 网关、ping 外网 IP
能 ping 通 IP 但打不开网页4 传输层 / 7 应用层检查 DNS、检查防火墙
网页打开慢4 传输层 / 7 应用层测带宽、查服务器负载
视频卡顿3 网络层 / 4 传输层测延迟、测丢包
邮件发不出去7 应用层检查 SMTP 设置、端口是否被封

症状 → 层次:一张更细的对照表

上面那张表适合入门。真正在工位上排障时,你需要的是更精确的"症状指纹"——不同层次的故障会呈现出相当不同的特征,学会读这些特征能省下大量时间:

这张表比上面那张细,用法也不一样:上面那张是"哪儿不舒服去哪个科",这一张是"这个症状最可能是什么病"。好的医生看病人走进门的姿势就能猜出八成——网络排障也一样,很多症状本身就是指纹。

症状特征最可能的层验证手段
网卡显示"未识别的网络"、灯不亮1 物理层ip link / ethtool eth0 看 Link detected
速率协商成了 10 Mbps 半双工1 物理层ethtool,通常是线材差或接口老化
能 ping 网关,ping 不通同网段某台机器2 链路层arp -a 看有没有学到对方 MAC;查 ARP 冲突
IP 是 169.254.x.x2/3 层DHCP 失败,系统自分配了链路本地地址
ping 通网关,ping 不通 8.8.8.83 网络层ip route 看默认路由;traceroute 看断在哪跳
traceroute 中途开始全是星号3 网络层可能真断了,也可能只是中间设备禁 ICMP
ping 通但 telnet 端口不通4 传输层防火墙或 ACL 拦了;nc -zv 复测
连接建立后立刻被断(收到 RST)4 传输层抓包看 RST 是谁发的;常见于服务未监听或被主动阻断
小请求正常,大文件卡死3/4 层典型 MTU 问题,用 ping -f -l 二分测 MTU
时快时慢、有明显重传4 传输层Wireshark 过滤 tcp.analysis.retransmission
浏览器报证书错误 / NET::ERR_CERT_*表示层openssl s_client 看证书链和有效期;检查系统时间
能 ping IP,域名打不开7 应用层DNS 问题,dig / nslookup 换 DNS 试
返回 502 / 5047 应用层反代到后端断了或超时,看反代和后端两侧日志
只有部分用户有问题3 或 7 层可能是 DNS 分区解析、CDN 某节点异常、或灰度发布

有两个反直觉的坑值得单独强调。第一,"ping 不通"不等于"网络不通"。大量服务器和防火墙默认丢弃 ICMP,所以 ping 失败但 443 端口完全正常是常态。判断服务可用性应该用 nc -zv host portcurl,不要用 ping。

第二,"能 ping 通"也不代表这一层就没问题。ping 用的是几十字节的小包,而 MTU 故障只在大包时才显形;ping 走的是 ICMP,而 QoS 策略可能对 TCP 和 ICMP 完全不同。测试用的包必须和真实业务的包尽可能相似,否则测出来的结论不可迁移。

这两个坑用大白话再说一遍。第一:"ping 不通"不等于"网不通"——很多服务器压根就不理 ping,好比一户人家规定"敲门一律不应,有事请打电话"。你敲门没人应,不代表家里没人。第二:"ping 通了"也不代表没问题——ping 用的是几十字节的小包,而 MTU 故障只在大包时才现形。好比你拿一支笔试了试门缝能过,就断定沙发也搬得进去。

一句话总结每层

最后把五层压成五句能随口说出来的大白话,比任何图表都管用。记住这五句,遇到问题时你至少知道该往哪个方向看。

Recap · 收束

分层模型不是"考试知识点",是"排查问题的地图"。记住:物理层看线、链路层看本地、网络层看路由、传输层看端口、应用层看服务
下次网络出问题,先问自己:"这是哪一层的问题?"——你就已经比 90% 的人更懂网络了。

☰ 主页
Xue Hai Wu Ya · Network · § 2.3 · Layers in Action