分类地址的关键在「首位模式」:不用掩码,看开头几个比特就知道是哪一类。 这是 1981 年的设计,那时候「查表」比「算」贵。
4.3.2 讲了「网络位和主机位」,这一节讲「分界线怎么由首位决定」。 D 类多播和 E 类保留在这里出场,4.3.5 会把 D 类展开。
一、五类,五个前缀
第一段的数字范围和首位模式是一一对应的:
| 类别 | 首位 | 第一段 | 掩码 |
|---|---|---|---|
| A | 0 | 1 到 126 | /8 |
| B | 10 | 128 到 191 | /16 |
| C | 110 | 192 到 223 | /24 |
| D 多播 | 1110 | 224 到 239 | — |
| E 保留 | 1111 | 240 到 255 | — |
第二列和第三列是同一件事的两种写法:「0 开头」意味着第一段小于 128,所以是 0 到 127; 「10 开头」意味着第一段在 128 到 191 之间。 所以「看第一段数字就能分类」不是巧合,是二进制前缀的直接结果。 这种设计在 1981 年是有道理的:路由器收到一个地址,只要看最高几位就能判断「网络部分多长」, 不用查表、不用配置。 在那个「内存以 KB 计」的年代,这是实打实的性能。
二、五类各占多少
按首位模式切,32 位空间被分得很整齐:
| 类别 | 占空间 | 地址数 |
|---|---|---|
| A | 1/2 | 50% |
| B | 1/4 | 25% |
| C | 1/8 | 12.5% |
| D | 1/16 | 6.25% |
| E | 1/16 | 6.25% |
加起来正好 100%:因为首位模式是「前缀码」: 0、10、110、1110、1111 这五个前缀刚好把所有可能的情况分完。 这个性质在编码里叫「前缀码无歧义」,和「哈夫曼编码不会混淆」是同一个道理。 所以「分类地址切得干净」是真的:它没有重叠、没有空隙。 问题只在于「切的比例不合适」—— 一半给了 A 类(128 个网段),八分之一给了 C 类(两百多万个网段)。 这个比例反映的是 1981 年的想象:「世界上只会有一百多个大网络」。
三、A 类为什么从 1 开始
0 和 127 这两段被单独留了出来:
| 地址段 | 用途 | 能不能分配给机构 |
|---|---|---|
| 0.0.0.0/8 | 「本网络」 | 不能 |
| 127.0.0.0/8 | 回环 | 不能 |
| 1.0.0.0/8 到 126.0.0.0/8 | 可分配 | 能 |
第一行那个「本网络」是个特殊含义:0.0.0.0 表示「不知道自己的地址」, 所以 DHCP 请求的源地址就是 0.0.0.0。 而「0.0.0.0/8 里的某个地址」在早期表示「这个网络上的某台主机」,现在几乎不用了。 第二行是回环:127.0.0.1 就是「我自己」, 整个 127/8 都指向本机,所以它不消耗任何网络资源。 这也是「为什么本机服务用 127.0.0.1 访问最快」的原因——数据根本没出网卡。 所以 A 类实际能分的是 126 个:128 减掉 0 和 127 这两段。 算地址总量时用 126 还是 128,会差出 1.6%。 这个差别在「说清楚口径」时很重要,写笔记时别把两个数混着用。
四、动手 Demo:五类地址,看头几个比特就知道
先看五类的首位模式与范围,再算各类实际能分多少地址。 注意 A 类只有 126 个网段能分,0 和 127 被留用了。
blocks = [('A 类', 126, 2 ** 24), ('B 类', 16384, 2 ** 16),
('C 类', 2097152, 2 ** 8)]
total = 0
for name, cnt, size in blocks:
n = cnt * size
total += n
print('%-5s %8d 个网 x %8d = %.3e' % (name, cnt, size, n))
print('合计 %.3e,占 %.1f%%' % (total, 100.0 * total / 2 ** 32))
实跑输出:
--------------------------------------------------------------------
五类地址,看头几个比特就知道
--------------------------------------------------------------------
**分类地址的关键在「首位模式」:不用掩码,看开头就知道是哪一类。**
**这是 1981 年的设计,那时候「查表」比「算」贵。**
类别 首位模式 第一段范围 默认掩码
-------------------------------------------------------
**A** **0** **1 到 126** **/8**
**B** **10** **128 到 191** **/16**
**C** **110** **192 到 223** **/24**
D(多播) 1110 224 到 239 —
E(保留) 1111 240 到 255 —
**第二列是「模式」,第三列是「范围的十进制写法」**:
**两者是一回事——0 开头就是 0 到 127,10 开头就是 128 到 191。**
**所以「看第一段数字就能分类」这件事,是二进制前缀的直接结果。**
**注意 A 类是从 1 开始的**:**0.0.0.0/8 被留作「本网络」,127/8 被留作回环**,
**所以 A 类实际能用的是 1 到 126 共 126 个网络。**
**算一下各类实际能分的地址总量**:
**A 类:126 个网乘 16777216,得 2.114e+09 个地址**
**B 类:16384 个网乘 65536,得 1.074e+09 个地址**
**C 类:2097152 个网乘 256,得 5.369e+08 个地址**
**三者相加 3.725e+09,占 2 的 32 次方的 86.7%**
**如果按「一个网都不浪费」算,三类正好覆盖 87.5%**,**差掉的那 0.8% 就是 0/8 和 127/8 这两段。**
**所以分类地址的问题不是「算错」,是「切得太粗」**——
**A 类一个网段 1677 万个地址,谁拿了都用不完。**
86.7% 和 87.5% 这两个数要分清: 87.5% 是「A、B、C 三类理论上占的空间」(1/2 加 1/4 加 1/8); 86.7% 是「扣掉 0/8 和 127/8 之后实际能分的」。差的那 0.8% 就是这两段。 写文档时用哪个数,取决于「你说的是理论还是实际」。 「首位模式」这套设计有个现代版的继承者:IPv6 的格式前缀。 2000::/3 是全局单播、fe80::/10 是链路本地、fc00::/7 是唯一本地—— 思路完全一样:看开头几位就知道「这地址干什么用的」。 区别是 IPv6 的前缀可以很长,不必挤在「首位」那么几个比特里。 最后说一个「分类地址还在用的地方」:很多系统的「地址类型判断」还是按老规矩写的, 比如「10 开头是内网」「192.168 开头是内网」。 这些判断在 CIDR 时代其实不严谨(10.0.0.0/8 只是个前缀), 但因为「私有段恰好是按类别挑的」,所以一直没出事。
30 秒实验
- 算一下:126 个 A 类网段一共覆盖多少地址?占 2 的 32 次方多少?
- 想一下:为什么 127/8 整段都指向本机?
- 想一下:首位模式为什么能做到「无歧义」?
常见误区
- 以为「A 类有 256 个网段」。 只有 128 个 /8,能分的是 126 个。
- 以为「分类是软件规定的」。 是首位模式的数学结果,看第一段数字就能判断。
- 以为「分类地址完全没用了」。 现代地址分类判断还按它写, IPv6 的前缀设计也继承了同一思路。
自测三问(点开对答案)
1. B 类的首位模式是什么? —— **10**,所以第一段是 128 到 191,默认掩码 /16。 2. 五类加起来为什么正好 100%? —— **0、10、110、1110、1111 这五个前缀把 32 位空间分完了**,没有重叠也没有空隙。 3. A 类为什么只有 126 个可用网段? —— **0.0.0.0/8 留给「本网络」、127.0.0.0/8 留给回环**,128 减 2 得 126。下一节看广播地址:主机位全 1 的那个特殊值。
- ☐ (本节完,下一节 4.3.4 广播地址)