模块五 · 链路层和局域网
一次 Web 请求的完整历程
前面学习了应用、运输、网络与链路的主要机制,现在用一次网页请求串起它们。无线与安全的深入机制还在后续模块;本章先明确场景和已有配置,再看各层怎样协作。
本章要解决的问题:前面学习了应用、运输、网络与链路的主要机制,现在用一次网页请求串起它们。无线与安全的深入机制还在后续模块;本章先明确场景和已有配置,再看各层怎样协作。
本章的证据来源:概念讲法参考教材§6.7,纸书336–340页(PDF355–359页),具体出处见章末。旧稿的命令与数值属于历史转述,相关附件未随当前项目提供,本次没有重新采集或运行原实验;模型计算、协议规则与观察不能互相替代。
先从一个例子理解概念
一台刚接入网络的电脑打开网页,可能先配置地址,再解析名字、找到下一跳、建立连接并发送HTTP请求。本章把已学机制串起来。
准备工作与应用请求
地址配置、域名解析和下一跳发现为通信提供条件;HTTP请求表达应用操作。实际过程取决于已有配置和缓存,不是每次点网页都从零开始。
报文经过各层
应用消息通过运输、网络与链路传送;不同位置看到的地址、封装和内容可能不同。观察一个位置的报文,不能假定它在整条路径上完全不变。
先说清楚本章的位置
这是一次总复习。如果你是从头读下来的,这一章应该有一种"每个环节都认识"的感觉;如果是跳着读的,这一章可以当索引用 —— 每个环节都注明了在哪一章细讲。
而且这一章会做一件前面没做过的事:把"教材里的干净网络"和"本机的真实环境"并排对照。
因为本机装了代理,很多环节的实际行为和"标准流程"不一样。把两个版本摆在一起,你才能分清哪些是网络的常态、哪些是本机特有的。
场景与环境
你要访问: https://example.com/
本机环境: WLAN 192.168.31.215/24,网关 192.168.31.1
装了代理(FlClash / verge-mihomo),有 TUN 网卡 198.18.0.1/30
DNS 被代理接管第 1 步(应用层):域名要先变成 IP
浏览器拿到的是一个域名,但网络只认 IP。所以第一件事是 DNS 查询。
本机实测结果:
example.com -> 198.18.0.205注意这个地址:198.18.0.0/15 是 RFC 2544 定义的基准测试保留段 —— 真实世界的 example.com 不在这里。
真实网络里: example.com → 93.184.216.34(真实服务器)
本机: example.com → 198.18.0.205(代理给的假地址)这叫 fake-IP:代理先给你一个假地址,等你的程序去连这个假地址时,代理从地址反查出你真正想访问的域名,再去真实地建立连接。
为什么代理要这么做? 因为它的分流规则是按域名写的("这个域名走代理、那个直连"),但它拿到的是一个已经解析好的 IP —— 丢了域名信息就没法分流。用假地址把域名"暂存"起来,就解决了这个问题。
第 2 步(网络层):决定这个包从哪出去
有了目的 IP,内核要查路由表决定从哪个接口发、交给谁。
本机实测(Find-NetRoute):
接口=FlClash 下一跳=198.18.0.2注意走的不是物理网卡,而是 TUN 虚拟网卡。 原因是:
| 路由 | 接口 | 度量 |
|---|---|---|
0.0.0.0/0 → 192.168.31.1 | WLAN | 较高 |
0.0.0.0/0 → 198.18.0.2 | FlClash | 更低(优先) |
两条默认路由并存,代理那条度量更低,所以赢了。
这一步用到的机制是最长前缀匹配 —— 本机路由表里有 34 条 Local + 2 条 NetMgmt 路由,包括大量 /32 主机路由;前缀越长越优先,长度相同才比度量。
第 3 步(链路层):找到下一跳的 MAC 地址
IP 决定了"交给谁",但要在链路层真的把帧发出去,还得知道下一跳的 MAC 地址。
本机实测(邻居缓存):
192.168.31.1 -> A4-39-B3-0B-AB-19 状态 Reachable而 TUN 网卡那一侧查不到 MAC —— 因为 TUN 工作在 IP 层,根本没有二层地址。这个细节在《MAC 地址》那一章第一次出现时很突兀,现在已经能解释了。
这一步用的是 ARP:广播问"谁是 192.168.31.1",对方单播回答自己的 MAC。
第 4 步(链路层):组帧,发出去
现在可以把帧组装起来了。本机实测重建出的帧头(用 tools/frame-anatomy.ps1 从系统状态重建,不是抓包):
┌─ 链路层(以太网帧头,14 字节)
│ 目的 MAC : A4-39-B3-0B-AB-19 ← 网关的 MAC(不是目标服务器的!)
│ 源 MAC : 44-38-E8-0A-55-23 ← 本机无线网卡
│ 类型 : 0x0800 (IPv4)
├─ 网络层(IPv4 头,20 字节)
│ 源地址 : 192.168.31.215
│ 目的地址 : 3.1.29.57
│ 协议 : 6 (TCP)
│ TTL : 128这里有一个最容易搞混的点,值得再强调一次:
帧长的约束也在这一步生效:以太网帧最小 64 字节(不足要填充)、最大 1518 字节;MTU 1500 字节 —— 这是《封装与解封装》里用 ping -f -l 实测出来的边界(1472 / 1473)。
第 5 步(传输层):建立 TCP 连接
HTTP 要用 TCP,所以要三次握手。
客户端 ──SYN(序号 x)──────────→ 服务器
客户端 ←─SYN+ACK(序号 y,确认 x+1)─ 服务器
客户端 ──ACK(确认 y+1)────────→ 服务器本机实测:在《套接字编程》那一章的实验里,connect() 返回的时候三次握手已经完成了 —— 这个"阻塞一会儿然后返回"的行为,就是握手在编程接口上的投影。
源端口是内核自动分配的,从 Windows 的动态端口范围 49152~65535(共 16384 个) 里挑一个。
这一步还确定了"四元组":源 IP、源端口、目的 IP、目的端口 —— 它是这条连接的唯一标识,也是后续所有状态(哪个连接在等确认、哪个连接该往哪转发)的依据。
第 6 步(应用层之下):TLS 握手
因为是 HTTPS,TCP 建好之后还要做 TLS 握手 —— 协商算法、验证证书、生成会话密钥。
本机实测(curl -v):
github.com → ALPN: h2 TLSv1.3
cloudflare.com → ALPN: h2 TLSv1.3
www.baidu.com → ALPN: http/1.1 TLSv1.2两个值得注意的地方:
① ALPN 是在 TLS 握手的第一个包里就协商的,这样服务器在你还没发请求之前就知道该用 HTTP/2 还是 HTTP/1.1 —— 省掉了一个往返。
② 同一台机器访问不同网站,协商结果不同。 这不是本机配置差异,而是服务器支持的不同(baidu 没启用 h2 和 TLSv1.3)。和第 6 模块 Wi-Fi 那个"网卡支持 WPA3 但连的是 WPA2"是同一类现象:能力支持 ≠ 实际使用。
第 7 步(应用层):发请求,收响应
真实报文(本机 curl -v 抓到的应用层对话):
> GET / HTTP/1.1
> Host: www.cloudflare.com
> User-Agent: curl/8.21.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< CF-Cache-Status: HIT
< Age: 3最后两行说明这个响应来自 CDN 节点的缓存,没有回源到原始服务器(Age: 3 表示这份缓存 3 秒前放入)。
注意 Connection: keep-alive —— 这条连接不会用完就关,后续请求可以复用。这就是为什么打开一个网页时不是每个图片都建一条新连接。
如果是 HTTP/2,复用会更彻底:本机实测过 HTTP/1.1 用 5 条 TCP 连接、HTTP/2 只用 1 条(同一批请求)。
第 8 步:结束或保持
请求完成后有两种可能:
| 情况 | 会发生什么 |
|---|---|
| 连接被复用 | 什么都不做,等下一个请求 |
| 需要关闭 | 四次挥手(因为 TCP 是全双工,两个方向各要一对 FIN/ACK) |
本机实测了一个和关闭有关的数字:主动关闭方会在 TIME_WAIT 状态停留约 116 秒(不是教科书常说的"2 分钟"或"120 秒")。
TIME_WAIT 的意义:让主动关闭方还能重发最后一个丢失的 ACK,并让这条连接的旧包在网络里自然消失,避免它们串到新连接上。
总表:一次请求的完整链条
这张表就是这套教程的总复习。 每一行都能点回对应的章节:
| # | 在哪一层 | 做什么 | 用什么协议 | 本机实测 | 细节在哪一章 |
|---|---|---|---|---|---|
| 1 | 应用层 | 域名 → IP | DNS | example.com → 198.18.0.205(fake-IP) | 《DNS 与 Fake-IP》 |
| 2 | 网络层 | 决定从哪出去 | 路由表 | 走 FlClash,下一跳 198.18.0.2 | 《路由与最长前缀匹配》 |
| 3 | 链路层 | 找下一跳的 MAC | ARP | 网关 MAC A4-39-B3-0B-AB-19,Reachable | 《ARP》《MAC 地址》 |
| 4 | 链路层 | 组帧发出 | 以太网 | 目的 MAC = 网关;MTU 1500 | 《以太网帧》《封装与解封装》 |
| 5 | 传输层 | 建立连接 | TCP 三次握手 | connect() 返回即握手完成 | 《TCP 握手与挥手》 |
| 6 | 传输层之下 | 加密与协商 | TLS + ALPN | 协商出 h2 / TLSv1.3(网站而异) | 《HTTPS 与 TLS》 |
| 7 | 应用层 | 请求与响应 | HTTP | 200 OK,CF-Cache-Status: HIT | 《HTTP》 |
| 8 | 传输层 | 复用或关闭 | keep-alive / 四次挥手 | TIME_WAIT ≈ 116 秒 | 《TCP 握手与挥手》 |
注意这个顺序里有一个"倒着走"的感觉:从第 1 步到第 8 步,你看到的是应用层 → 网络层 → 链路层 → 传输层 —— 因为"找地址"和"建连接"这两件事在顺序上是交错的。真实的软件栈就是这样:应用层发起,往下逐层准备,最后逐层返回。
关键:本机这一趟被改写了
上面每一步的"本机实测"里,有一半和教材流程不一样。 把它们并排对照:
| 步骤 | 教材流程(干净网络) | 本机实际 | 谁改写了它 |
|---|---|---|---|
| 1 DNS | 递归/迭代查到真实 IP | 返回假地址 198.18.x.x | 代理(fake-IP) |
| 2 路由 | 走物理网卡到网关 | 走 TUN 网卡到 198.18.0.2 | 代理(接管默认路由) |
| 3 ARP | 查目标或网关的 MAC | 网关那侧正常;TUN 侧没有二层 | TUN 的特性 |
| 4 组帧 | 目的 MAC = 网关 | 同上,且实际帧可能不经过物理网卡 | 代理 |
| 5 TCP | 端到端握手到服务器 | 代理在本地先替对端握手 | 代理 |
| 6 TLS | 端到端与服务器协商 | 无法确认是否端到端 | 代理(可能中间人) |
| 7 HTTP | 直接连服务器 | CF-Cache-Status: HIT 来自 CDN | CDN(正常) |
| 8 关闭 | 与服务器挥手 | 本机测的是到代理那一跳的 TIME_WAIT | 代理 |
这张对照表是本章最有价值的东西。 它说明:
反向练习:如果某一步坏了,会看到什么
把这条链反过来用,就是排错。每一层的故障都有它特定的症状:
| 坏在哪一步 | 你看到的症状 | 怎么确认 | 在哪一章 |
|---|---|---|---|
| 1 DNS | 能上 QQ 不能开网页 | Resolve-DnsName 查一下 | 《DNS 与 Fake-IP》 |
| 2 路由 | 内网通、外网不通 | Find-NetRoute 看走哪条 | 《路由与最长前缀匹配》 |
| 3 ARP | 网关 ping 不通 | 看邻居缓存是 Incomplete 还是 Reachable | 《ARP》 |
| 4 帧/MTU | 小页面能开、大文件传不完 | ping -f -l 探路径 MTU | 《封装与解封装》 |
| 5 TCP | 连接超时或被拒绝 | 超时 = 被丢;RST = 端口没开 | 《TCP 握手与挥手》 |
| 6 TLS | 证书报错 | 看证书链和有效期 | 《HTTPS 与 TLS》 |
| 7 HTTP | 4xx / 5xx | 看状态码分界 | 《HTTP》 |
| 8 关闭 | 连接泄漏、端口耗尽 | 看 CLOSE_WAIT 是否堆积 | 《TCP 握手与挥手》 |
这张表的作用是:给你一条排查顺序。 它是第 8 模块《分层排错法》那套方法的简化版 —— 那边有完整的七步体检清单。
常见误解
误解一:「打开一个网页只建立一条连接」
取决于协议版本。 本机实测:同一批 5 个请求,HTTP/1.1 用了 5 条 TCP 连接,HTTP/2 只用 1 条。 HTTP/1.1 每个请求独占一条连接(虽然有 keep-alive 可以复用,但浏览器因为队头阻塞会主动开多条并行);HTTP/2 用多路复用,多条流共享一条连接。
误解二:「一次访问只查一次 DNS」
实际上要查好几次。 一个网页通常包含 HTML、CSS、JS、图片,它们往往在不同的域名下(比如 CDN 域名),每个域名都要单独解析。这就是为什么"能上 QQ 不能开网页"这种症状会出现 —— 主域名的 DNS 通了,某个资源域名的没通。
误解三:「目的 MAC 就是目标服务器的 MAC」
不是,是网关的。 本机实测重建出的帧头里,目的 IP 是 3.1.29.57,而目的 MAC 是网关的 A4-39-B3-0B-AB-19。 因为帧只在同一段链路内有效 —— 包要跨网络,本机只能交给网关,让网关重新封装。IP 全程不变,MAC 每一跳都换。
误解四:「HTTPS 就一定是端到端安全的」
在装了中间人的环境里不一定。 本机流量经过 TUN 代理,无法从外部确认 TLS 握手是端到端与真实服务器完成的,还是被代理接管了(《HTTPS 与 TLS》那一章明确标注了这个局限)。 判断依据只有间接的(不同网站协商结果不同说明至少在正常转发),不是直接证据。
误解五:「本教程的实测数据等于网络的标准行为」
本章的对照表直接反驳这一点。 8 个步骤里有 6 个在本机被改写了。 所以看任何网络数据前都要先问:这个观测环境里有没有东西在替我做事? —— 这是贯穿整套教程的一个提醒。
本章小结
| 结论 | 类型 |
|---|---|
| 一次 Web 访问要依次经过 DNS、路由、ARP、组帧、TCP、TLS、HTTP、关闭八个环节 | 标准 |
实测:example.com 在本机被解析为 198.18.0.205(fake-IP 段) | 实测 |
| 实测:本机两条默认路由,代理那条度量更低因而优先 | 实测 |
实测:网关邻居缓存为 Reachable,MAC 为 A4-39-B3-0B-AB-19 | 实测 |
| 实测:重建帧头显示目的 IP 是最终目标而目的 MAC 是网关 | 实测 |
实测:connect() 返回即三次握手完成 | 实测 |
| 实测:不同网站协商出不同 ALPN 与 TLS 版本(h2/TLSv1.3 vs http1.1/TLSv1.2) | 实测 |
| 实测:同一批 5 个请求,HTTP/1.1 用 5 条连接、HTTP/2 用 1 条 | 实测 |
实测:响应含 CF-Cache-Status: HIT、Age: 3,来自 CDN 缓存 | 实测 |
| 实测:主动关闭方 TIME_WAIT 约 116 秒 | 实测 |
| 本机八个环节中有六个被代理改写,与教材流程不同 | 实测 + 对照 |
| 每一层的故障有特定症状,可反向用于排错 | 推理 |
| 一个网页通常涉及多个域名的 DNS 查询 | 标准 |
自测题
7 题 · 先自己答,再展开对照
按顺序说出一次 HTTPS 访问经过的环节,各在哪一层?
八个环节:
① 应用层 DNS 把域名变成 IP
② 网络层 查路由表决定从哪个接口出去
③ 链路层 ARP 找到下一跳的 MAC
④ 链路层 组帧发出(受 MTU 与最小帧长约束)
⑤ 传输层 TCP 三次握手建立连接
⑥ 传输层之下 TLS 握手(HTTPS 才有),ALPN 协商应用层协议
⑦ 应用层 HTTP 请求与响应
⑧ 传输层 连接复用或四次挥手关闭为什么本机解析
example.com得到的是198.18.0.205而不是真实 IP?代理为什么要这样做?因为本机装了代理,它返回的是 fake-IP。198.18.0.0/15是 RFC 2544 的基准测试保留段,真实服务器不在那里。
代理这样做是因为它的分流规则按【域名】写("这个域名走代理、那个直连"),但它拿到的是已经解析好的 IP —— 丢了域名信息就没法分流。用假地址把域名"暂存"起来,等程序来连这个假地址时再反查回域名,就解决了这个问题。重建出的帧头里,目的 IP 是最终服务器,目的 MAC 却是网关。为什么?
因为帧只在同一段链路内有效。 目标3.1.29.57不在本网段,所以本机只能把包交给网关转发 —— 而"交给网关"在二层就体现为帧的目的 MAC 填网关的 MAC。
网关收到后脱掉这个帧头,重新封装一个新的帧头(目的 MAC 换成下一跳)再发出去。IP 全程不变,MAC 每一跳都换。同一个网页里的多个请求,HTTP/1.1 和 HTTP/2 在建连接这件事上有什么不同?
HTTP/1.1 会开多条并行连接,HTTP/2 只用一条。
本机实测:同一批 5 个请求,HTTP/1.1 用了 5 条 TCP 连接,HTTP/2 只用了 1 条。
原因是 HTTP/2 用多路复用(多条流共享一条连接),而 HTTP/1.1 因为队头阻塞的问题,浏览器会主动开多条连接来并行加载资源。"能上 QQ 不能开网页"最可能坏在哪一步?为什么?
最可能在 DNS 那一步。 因为 QQ 这类程序大量使用 IP 直连或自己维护的长连接,对 DNS 依赖小;而网页必须先用域名解析出 IP。
所以"能上 QQ 不能开网页"恰好说明网络部分是通的(IP 层、传输层正常),坏的是域名解析。 确认方法:Resolve-DnsName查询,或临时换个 DNS 服务器试试。本机这次访问的八个环节里,有几个和教材流程不一样?这说明什么?
八个环节里有六个和教材流程不一样(DNS 返回假地址、路由走 TUN、ARP 的 TUN 侧没有二层、TCP 由代理本地代替握手、TLS 无法确认是否端到端、TIME_WAIT 测的是到代理那一跳)。
这说明:本教程大量的"实测"测的是"这台机器 + 代理"的行为,不是"网络本身"的行为。
所以每一章都注明观察条件、把结论分成实测/标准/判断三类 —— 知道自己的数据是在什么条件下得到的,比数据本身更重要。一个网页只查一次 DNS 吗?
不只一次。 一个网页通常包含 HTML、CSS、JS、图片,而且这些资源往往放在不同的域名下(比如专门的 CDN 域名、静态资源域名)。每一个域名都要单独做一次 DNS 解析。
这也解释了为什么"某些资源加载不出来"可能是某一个域名的 DNS 有问题,而不是整个网络不通。
参考资料与适用范围
- 《计算机网络:自顶向下方法(原书第8版)》§6.7,纸书336–340页(PDF355–359页):本章概念与机制的对应教学章节,引用时需保留模型与版本条件。
- 教材作者配套教学资源入口:网站目前显示的教材版本与用户提供的第8版可能不同,页码以本章列出的中文第8版为准。
修订核对日期:2026-10-13。本次补充概念入口与教材出处;旧稿的具体数值为历史观察,未重新实测。相关脚本和完整日志未随当前项目提供,不能仅凭转述断言实验已复核,也不据此断言数据造假。