第 3 层管「终点在哪」,第 2 层管「这一跳交给谁」——这是全书最重要的一条分界线。 路由器只查不改 IP 头,却要重写每一次的链路层头。
第三章讲的全是「这一跳」,从这一章开始讲「终点」。 3.1 那句「不管最终去哪」在这里得到兑现:接手的这个人就是 IP。
一、一个包在路上
把一次「从你的电脑到服务器」拆开看,变化的东西只有一样:
| 位置 | 源 MAC | 目的 MAC | IP 头 |
|---|---|---|---|
| 主机 A 网卡 | 本机网卡 | 路由器 1 | 不变 |
| 路由器 1 出 | 路由器 1 右口 | 路由器 2 | 不变 |
| 路由器 2 出 | 路由器 2 右口 | 服务器 | 不变 |
第三列一直在换,第四列一直没动:这就是「链路层地址只管这一段」的直接证据。 每过一台路由器,链路层头就被拆掉重写一遍,而 IP 头从头到尾是同一个。 所以「经过的跳数越多,链路层越忙,网络层越省」: 中间设备只需要看它该看的那一层——交换机看 MAC,路由器看 IP,各干各的。
二、分界线的准确位置
三层各管什么,一句话能说清:
| 层 | 地址 | 管到哪 | 谁看 |
|---|---|---|---|
| 第 2 层 | MAC | 一段链路 | 交换机 |
| 第 3 层 | IP | 整条路径 | 路由器 |
| 第 4 层 | 端口号 | 一台主机内 | 主机自己 |
第一行的「一段链路」是精确的说法:不是「一个网段」,是「一条物理上能直达的信道」。 所以两台主机之间如果隔了一台路由器,它们就不在「一段链路」上——哪怕 IP 网段是同一个。 第二行的「整条路径」也是精确的:IP 地址从源到目的都不变, 所以它描述的其实是「终点」,而不是「怎么走」。 「怎么走」是路由表的事——同一对源和目的,换个时间可能走不同的路,但 IP 头是一样的。
三、为什么这样分
分成两层的收益只有一条,但足够大:中间设备不用知道全局。 交换机只需要一张 MAC 表,不用知道互联网有几十亿个地址; 路由器只需要一张路由表,不用记住每台主机的 MAC。 如果只有一个地址体系会怎样: 要么所有设备都用 MAC 寻址,那路由器就得存下全球每一块网卡的地址(不可能); 要么所有设备都用 IP 寻址,那每次换网卡都要改 IP(也不合理)。 所以这条分界线的本质是「信息的分布」:MAC 是硬件出厂就定好的、不可聚合的编号; IP 是可以按前缀聚合的、有层次的编号。 只有「可聚合」,路由器才可能用一张几千条的表覆盖整个互联网。 顺带说一句「第 3 层」这个编号:OSI 的七层里,网络层是第三层, 所以「三层设备」指的就是路由器,「二层设备」指交换机—— 这两个说法在工程里天天用,来源就在这里。
四、动手 Demo:一个包在路上,哪一层在变
把一次跨三台路由器的传输摊开,看每一段用的是哪个地址。 注意最后一列:IP 头从头到尾「不变」。
hops = [('主机 A 网卡', '9C-B6-..-0F', '路由器 1'),
('路由器 1 出', '路由器 1 右口', '路由器 2'),
('路由器 2 出', '路由器 2 右口', '服务器')]
for where, src, dst in hops:
print('%-14s 源 MAC %-12s 目的 MAC %-10s IP 头 不变'
% (where, src, dst))
print('链路层头重写 %d 次,IP 头重写 0 次' % len(hops))
实跑输出:
--------------------------------------------------------------------
一个包在路上,哪一层在变
--------------------------------------------------------------------
**同一个包从你的电脑到服务器,IP 头只被「看」不被改,而链路层的头每过一台路由器就要换一次。**
**这就是「第 3 层管终点、第 2 层管这一跳」的具体样子。**
位置 这段的源 MAC 这段的目的 MAC IP 头
--------------------------------------------------------------
主机 A 网卡 9C-B6-..-0F 路由器 1 **不变**
路由器 1 进 路由器 1 左口 路由器 1 **不变**
路由器 1 出 路由器 1 右口 路由器 2 **不变**
路由器 2 出 路由器 2 右口 服务器 **不变**
**第三列一直在换,这才是「第 2 层地址」的含义**:**它只在「这一段」有效,换一段就重写。**
**而第四列的 IP 头从头到尾没动**——**它是「终点地址」,路由器只查不改(NAT 除外)。**
**算一下这个包被改了几次**:
**链路层头重写 4 次,IP 头重写 0 次,TCP 头重写 0 次。**
**所以「经过的跳数越多,链路层越忙,网络层越省」**——
**这是分层最直接的收益:中间设备只需要看它该看的那一层。**
「路由器只查不改 IP 头」这句话有个例外要说清:NAT 会改,而且改得很彻底(源地址、 源端口都换)。所以严格说「IP 头不变」只在「没有 NAT」的前提下成立。 但 NAT 是「网络边缘的一次性改写」,不是「每一跳都改」—— 这个区别很重要,否则会把 NAT 和路由混为一谈。 还有一个会改 IP 头的设备:防火墙的「地址转换」和「代理」。 代理是「重新发一个请求」,连 TCP 连接都是新的,而 NAT 是「只改头部字段、连接还是那条」。 两者的区别在于「谁在维持状态」。 最后记一个术语:「逐跳转发」这个词就是这个机制的正式名字。 每一台路由器只负责「把包交给下一个更接近终点的设备」, 它不需要知道完整路径——这和「源路由」(把整条路径写进包里)是相反的两种设计。
30 秒实验
- 想一下:如果只用 MAC 地址通信,路由器需要多大的表?
- 想一下:为什么「IP 地址不变」这句话在 NAT 场景下要打折扣?
- 在你电脑上 tracert 一个网站,数一下中间经过几台路由器。
常见误区
- 以为「IP 地址每一跳都会变」。 不变,变的是链路层地址。变的那个叫 NAT。
- 以为「MAC 只管一个网段」。 是「一段链路」,同一网段里隔了路由器就不算同一段链路。
- 以为「分层是为了好看」。 是为了「中间设备不用知道全局」,这才是它能扩展的前提。
自测三问(点开对答案)
1. 第 3 层和第 2 层的分工线在哪? —— **第 2 层管「这一跳交给谁」,第 3 层管「终点在哪」**,所以前者每跳都换、后者全程不变。 2. 为什么 MAC 地址不能当全球地址用? —— **它是平铺的、没有层次**,路由器无法用它聚合出「一大片去哪儿」。 3. 分层带来的最大收益是什么? —— **中间设备不用知道全局**:交换机只要 MAC 表,路由器只要路由表。下一节把这两层的关系再拧紧一点:IP 和 MAC 怎么配对。
- ☐ (本节完,下一节 4.1.2 网络层与数据链路层的关系)