📚 第四章 IP协议
📄 一句话概括

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 秒实验

  1. 算一下:40 字节的 TCP ACK 在 WiFi 上占多少?其中头占多少比例?
  2. 想一下:为什么 PPP 的头只有 5 个字节?
  3. 查一下你常用的一条链路,它的 MTU 是多少。

常见误区

  1. 以为「IP 屏蔽了所有底层差异」。 只屏蔽格式,不屏蔽能力,MTU 和延迟照样上传。
  2. 以为「头越小越好」。 要看好坏:PPP 头小是因为不需要地址, 换个场景(共享介质)就必须有地址。
  3. 以为「抽象化只对开发者有好处」。 运维要多查一层,因为问题会被「包装」起来。
自测三问(点开对答案) 1. IP 的抽象化具体省掉了什么? —— **上层不用知道底层的帧格式**,换介质不用改程序。 2. 为什么 WiFi 的头比以太网多 10 字节? —— **它要带三个地址**(源、目的、上一跳),因为空口是共享的。 3. 抽象化没省掉什么? —— **物理约束**:MTU、延迟、丢包率、开销比例都会一路上传。

下一节看 IP 的「无连接」:不打招呼就发,是优点还是缺点。

相关笔记