分组交换把大块数据切成小包,每包自己带头。 头是固定成本,所以包越小、头占的比例越高——这是「包大小」要折中的根本原因。
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 秒实验
- 把
HDR改成 48(加上以太网头 14 字节的近似值),看 28.00% 那一档会变成多少。 - 把总数据改成 10 KB,再跑一遍——看小数据量时头占比有多离谱,这就是「小请求很贵」的直接证据。
- 算一下每包载荷 576 时(老式默认值)的头占比,和 1460 对比,想想为什么这个默认值后来被改掉了。
常见误区
- 以为包切得越小越灵活。 头是固定成本,包越小头占比越高,100 字节一包时近三成带宽在传头。
- 以为乱序是网络故障。 分组交换的包独立路由,乱序是常态,IP 层根本不保证顺序, 重排是 TCP 的事。
- 以为丢包是设备不行。 队列满了丢包是设计选择,为的是不让延迟无限涨。 丢包本身就是拥塞信号。
自测三问(点开对答案)
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 节到此结束。下一节换个大问题:这些协议到底是谁定的?
- ☐ (本节完,下一节 1.4.1 计算机通信的诞生及其标准化)