IP 的抽象化说的是:它不关心底层是以太网、PPP 还是 WiFi。 但「装进去」有成本,而且每个介质的成本不一样——这些成本会一路上传。
4.2.2 讲「路怎么选」,这一节讲「路下面是各种不同的地」。 抽象化是 IP 最核心的设计,也是它最容易被误解的地方。
一、同一份数据,不同的壳
同样 1000 字节的 IP 包,装进四种介质,长度各不同:
| 链路 | 头 | 尾 | 线上一共 |
|---|---|---|---|
| 以太网 | 14 | 4 | 1018 |
| PPPoE | 22 | 4 | 1026 |
| PPP | 5 | 3 | 1008 |
| WiFi 数据帧 | 24 | 4 | 1028 |
第四行最贵:WiFi 的头 24 字节,比以太网多 10 个,因为无线要带三个地址(源、目的、 上一跳)。为什么多一个:空口是共享的,接收方要知道「这个帧是谁转给我的」。 第三行最便宜:PPP 只有 5 字节头,因为它「一根线只接两家」, 不需要地址——这正好和 3.5.1 讲的「点对点不需要地址」对上。
二、抽象化省了什么
省掉的是「上层要知道底层细节」这件事:
| 如果没有抽象 | 有了 IP |
|---|---|
| 每个应用要会拼四种帧 | 只交一个 IP 包 |
| 换介质要改程序 | 换介质不用改 |
| 每种介质一套编程接口 | 一套 socket 通吃 |
第一行是「工作量」的差别:写网页的人不需要知道这根线是铜的还是光的, 他只需要「往这个 IP 和端口写数据」。 这就是「窄腰」的实际收益(2.3.2 讲过)。 第二行是「可替换性」:从拨号换成光纤,应用一行代码都不用改, 因为换掉的只是「IP 下面那一层」。 这也是为什么「IP over everything」这句话能成立——它把「介质」变成了「可插拔的部件」。
三、抽象化没省掉什么
没省掉的是「物理约束」:MTU、延迟、丢包率、开销比例,全都会一路上传。 最典型的就是 MTU:IP 想把 1500 字节发出去,但下面那条链路只能装 1492, 于是要么分片、要么报错。 「抽象」不会让 1492 变成 1500——它只是让「上层不必亲自处理」,而不是「问题消失了」。 所以「IP 屏蔽了底层差异」这句话要精确地说:它屏蔽的是「格式差异」,不是「能力差异」。 格式差异(帧长什么样)上层确实不用管;能力差异(能装多大、多快、多可靠)上层一定要管。 不承认这一点,就会在排障时反复踩坑—— 4.5 的 MTU、3.5.4 的 MSS,全是这个「没屏蔽干净」的地方。 这也解释了一个设计上的取舍:IPv6 干脆把「分片」这件事从路由器手里收走了(4.6.8 会讲), 改成「源端必须自己探出路径 MTU」——既然屏蔽不干净,不如明确要求上层知道。
四、动手 Demo:同一个 IP 包,装进不同的链路层
把 1000 字节的 IP 包装进四种介质,看各自的封装开销。 注意 WiFi 那行:24 字节头,比以太网多 10 个。
ip = 1000
media = [('以太网', 14, 4), ('PPPoE', 22, 4),
('PPP', 5, 3), ('WiFi 数据帧', 24, 4)]
for name, head, tail in media:
print('%-12s 头 %2d 尾 %d 线上一共 %4d'
% (name, head, tail, ip + head + tail))
实跑输出:
--------------------------------------------------------------------
同一个 IP 包,装进不同的链路层
--------------------------------------------------------------------
**IP 的「抽象化」说的是:它不关心底层是以太网、PPP 还是 WiFi。**
**但「装进去」这件事有成本,而且每个介质的成本不一样。**
链路 头 尾 线上一共 说明
--------------------------------------------------------------------
以太网 14 4 1018 MAC 头加 FCS
PPPoE 22 4 1026 以太网加 PPPoE 加协议
PPP 5 3 1008 标志加地址加控制
WiFi(数据帧) 24 4 1028 三地址加 FCS
**第一列和第四列一起看**:
**同样 1000 字节的 IP 包,在以太网上占 1018 字节,在 WiFi 上占 1028 字节。**
**差的这 10 个字节就是「三地址帧」的代价**——**无线要多带一个地址(上一跳的)。**
**为什么无线要多带一个地址**:因为空口是共享的,接收方要知道「这个帧是谁转给我的」。
**所以「IP 屏蔽了底层差异」这句话要打个折**:
**上层不用管底层的格式,但底层的开销会一路传上来**——**MTU、MSS、分片阈值,全都被底层决定。**
**这就是 4.5 要讲的事。**
PPPoE 那 22 字节是「14 加以太网 + 6 加 PPPoE 头 + 2 加协议」: 它其实是「套了两层」——所以它的开销比以太网多 8,正好是 PPPoE 那一层。 这个「8」在 3.5.4 出现过,它最后变成了 MSS 少了 8。 「头越大,效率越低」这件事对小包最明显: 一个 40 字节的 TCP ACK,在 WiFi 上要占 40 加 24 加 4 得 68 字节,其中一半以上是头。 所以「小包多」的流量在任何介质上都不划算——这也是为什么「合并小包」是通用的优化手段。 最后一句要说清「抽象化」的边界:它让「写程序的人」不用管底层,但「运维的人」必须管。 所以「IP 屏蔽了底层」这句话,对不同角色含义不同—— 对开发者是「解放」,对运维是「多了一层要查」。
30 秒实验
- 算一下:40 字节的 TCP ACK 在 WiFi 上占多少?其中头占多少比例?
- 想一下:为什么 PPP 的头只有 5 个字节?
- 查一下你常用的一条链路,它的 MTU 是多少。
常见误区
- 以为「IP 屏蔽了所有底层差异」。 只屏蔽格式,不屏蔽能力,MTU 和延迟照样上传。
- 以为「头越小越好」。 要看好坏:PPP 头小是因为不需要地址, 换个场景(共享介质)就必须有地址。
- 以为「抽象化只对开发者有好处」。 运维要多查一层,因为问题会被「包装」起来。
自测三问(点开对答案)
1. IP 的抽象化具体省掉了什么? —— **上层不用知道底层的帧格式**,换介质不用改程序。 2. 为什么 WiFi 的头比以太网多 10 字节? —— **它要带三个地址**(源、目的、上一跳),因为空口是共享的。 3. 抽象化没省掉什么? —— **物理约束**:MTU、延迟、丢包率、开销比例都会一路上传。下一节看 IP 的「无连接」:不打招呼就发,是优点还是缺点。
- ☐ (本节完,下一节 4.2.4 IP属于面向无连接型)