📚 第一章 网络基础知识
📄 一句话概括

分组交换把大块数据切成小包,每包自己带头。 头是固定成本,所以包越小、头占的比例越高——这是「包大小」要折中的根本原因。

📝 本节和前面几节的关系

1.3.4 讲的是「一条报文怎么排」,这一节讲「报文怎么被运走」。 1.7.2 还会从「电路交换 vs 分组交换」的角度再讲一次,这里只讲分组本身的代价。

一、为什么要切

不切行不行?不行,三个理由:

问题 不切的后果 切开的好处
出错重传 整块重发,代价巨大 只重发坏的那个包
独占线路 一条流占满,别人等着 大家轮流用
长度上限 链路有最大帧长 天然不超限

第一行是最实际的理由:一兆字节的数据,中间错了一个比特,不切就得整块重发。 切成一千个包,只重发坏的那一个。 第二行是分组交换的思想核心: 它不是「给你一条线」,而是「把你的数据切成片,混在别人的片里一起走」。 代价是没有保证的带宽,好处是线路利用率极高。 第三行是被动约束:以太网一帧最多 1500 字节载荷,不切根本发不出去, IP 层会替你分片,但那是在更底下做的补救,效率更差。

二、头是固定成本

同样一兆字节,包越小,头越多:

每包载荷 包数 头占比
1460 719 2.03%
536 1957 5.26%
100 10486 28.00%

第一行 1460 就是「MTU 满打满算」的结果:1500 减去 IP 头 20、再减去 TCP 头 20,正好 1460。 第三行那一档,将近三成的带宽在传头:一千多个字节里,真正属于你的数据只有 100 字节。 所以小包传输的场景(语音、游戏操作)对带宽的利用率天然偏低,不是设备不行,是头太贵。 这三行也解释了为什么大文件下载快、小请求慢:不是线路快慢的问题,是「每次都要付一遍头钱」。 一个 100 字节的请求,在 1460 的包里,头占了 2.03%——可如果这个请求本身只有 100 字节, 头就占了它的一半以上。

三、切小了换来的三件事

包一旦独立,就必须自己解决三个问题:

问题 怎么发生的 谁来补
乱序 各包走的路不同,先后颠倒 序号 + 重组
丢失 队列满了被丢掉 确认 + 重传
重复 重传的包和原包都到了 序号去重

第一行是分组交换的固有属性:包是独立路由的,走的路不一样,到达顺序就不保证。 所以「先发的先到」这件事,在 IP 层根本不成立,要靠 TCP 用序号重新排好。 第二行那个「队列满了就丢」是设计选择,不是故障:网络设备宁可丢包也不肯无限排队, 因为排队到一定程度,延迟会大到让上层完全没法用。 丢包是拥塞信号,这是整个互联网 congestion control 的基础。 第三行是前两行的必然结果:既然要重传,就可能重复;既然可能有重复,就必须去重。 所以可靠传输的三件套——序号、确认、重传——是被分组交换逼出来的。

四、动手 Demo:分组交换,包越小头越贵

把同一份 1 MB 数据按三种包长切开,数包数与头的总字节。 头按 TCP 加 IP 共 40 字节算,这是最常见的口径。

TOTAL = 1024 * 1024
HDR = 40

print('%-12s %-10s %-14s %-16s %s'
      % ('每包载荷', '包数', '线上总字节', '全是头的字节', '头占比'))
print('-' * 74)
for pay in (1460, 536, 100):
    n = (TOTAL + pay - 1) // pay
    wire = n * (pay + HDR)
    hdr = n * HDR
    print('%-12d %-10d %-14d %-16d %.2f%%'
          % (pay, n, wire, hdr, hdr * 100.0 / wire))

实跑输出:

--------------------------------------------------------------------
分组交换,包越小头越贵
--------------------------------------------------------------------
**分组交换把大块数据切成小包,每包自己带头。**
**头是固定的,所以包越小、头占比越高。**

  每包载荷     包数      线上总字节     全是头的字节     头占比
  --------------------------------------------------------------
  1460         719       1069872        21296            2.03%
  536          1957      1103748        55172            5.26%
  100          10486     1342208        293632           28.00%

**同一份 1 MB 数据,按 MTU 满打满算只要 719 个包**(载荷 1460),
**切成 100 字节的小包要 10486 个,头开销从 21296 涨到 293632 字节。**

**这就是「分组大小」要折中的原因**:
**包太大,一个丢了重传代价高、还要分片;包太小,头开销吃掉带宽。**
**以太网定 1500 字节,是这两头折出来的结果。**

719 个包对 10486 个包,差十四倍多;头开销从 21296 字节涨到 293632 字节,差十三倍多。 注意「线上总字节」也跟着涨:2.03% 那档总共 1069872 字节,28.00% 那档 1342208 字节。 同一份 1 MB 数据,因为包长不同,实际占用的带宽差了 25%。 这个数只算了 IP 与 TCP 头,没算以太网头(14 字节)、帧间隔(12 字节)、前导码(8 字节), 所以真实开销比表里更大。 包数还影响另一件事:每包都要中断一次、查一次表、排一次队。 10486 个包对设备的包处理能力要求,比 719 个包高一个量级。

30 秒实验

  1. 把 HDR 改成 48(加上以太网头 14 字节的近似值),看 28.00% 那一档会变成多少。
  2. 把总数据改成 10 KB,再跑一遍——看小数据量时头占比有多离谱,这就是「小请求很贵」的直接证据。
  3. 算一下每包载荷 576 时(老式默认值)的头占比,和 1460 对比,想想为什么这个默认值后来被改掉了。

常见误区

  1. 以为包切得越小越灵活。 头是固定成本,包越小头占比越高,100 字节一包时近三成带宽在传头。
  2. 以为乱序是网络故障。 分组交换的包独立路由,乱序是常态,IP 层根本不保证顺序, 重排是 TCP 的事。
  3. 以为丢包是设备不行。 队列满了丢包是设计选择,为的是不让延迟无限涨。 丢包本身就是拥塞信号。
自测三问(点开对答案) 1. 为什么 1460 这个数会出现在「MTU 满打满算」那一档? —— **以太网 MTU 是 1500,减去 IP 头 20、TCP 头 20,正好 1460。** 这是不分片前提下能装的最大 TCP 载荷。 2. 同一份数据,包长从 1460 降到 100,头占比从多少涨到多少? —— **从 2.03% 涨到 28.00%**,包数从 719 涨到 10486,线上总字节也从 1069872 涨到 1342208。 3. 可靠传输的「序号、确认、重传」三件套是被什么逼出来的? —— **被分组交换本身**:包独立路由会乱序、队列满会丢包、重传会重复。 要在这之上做出可靠,只能靠序号排序、确认、去重重传。

第一章 1.3 节到此结束。下一节换个大问题:这些协议到底是谁定的?

相关笔记