互联网不是「被设计出来的网络」,是「都用同一套协议的网络」。 IP 是窄腰:上面无限种应用,下面无限种介质,中间只有它一个。
2.3.1 讲的是「互联网这个词」,这一节讲「它凭什么能连起来」。 这一节用一次域名解析就能验证「换掉网络层不动应用层」。
一、关系是「都用它」,不是「属于它」
两句话,方向完全不同:
| 说法 | 对错 | 为什么 |
|---|---|---|
| 「互联网属于 TCP/IP」 | 反了 | TCP/IP 是一套协议 |
| 「TCP/IP 属于互联网」 | 也反了 | 协议是公开的标准 |
| 「互联网 = 跑 TCP/IP 的网络」 | 对 | 是「都用」的关系 |
前两行都是「归属关系」,都不成立:TCP/IP 是 IETF 维护的公开标准,不属于任何组织; 互联网也不是「一个东西」,没有主体。 所以准确的说法是第三行:当足够多的网络都用同一套协议互联时,它们合起来就叫互联网。 这个理解很重要,因为它解释了「为什么没人能关掉互联网」: 要关掉它,得让所有网络同时停用 IP——而没有任何一个机构有这个权力。
二、窄腰结构
一张图能说清:
应用层 HTTP DNS SMTP SSH ……(无限多)
\ | | | /
传输层 TCP UDP
\ /
网络层 IP ← 窄腰
/ \
链路层 以太网 Wi-Fi 光纤 4G ……(无限多)
中间那个 IP 是唯一的「必经之路」:上面可以有无数种应用协议,下面可以有无数种传输介质, 但它们都必须穿过 IP 这一层。 这就是「窄腰」的好处:只需要把 IP 实现好,上下两头就能自由生长。 新加一种介质(比如 5G),只要它能承载 IP,上面所有应用立刻就能用,不需要任何应用改代码。 代价也很清楚:IP 本身很难改。 IPv4 地址不够用这件事,从 1990 年代就知道,但直到今天还在用 NAT 撑着—— 因为改 IP 就是改整个互联网的地基。
三、一次解析证明一切
「换掉网络层,应用层不动」这句话可以实测:
| 地址族 | 返回条数 | 应用代码要改吗 | |---|---| | IPv6 | 4 | 不用 | | IPv4 | 4 | 不用 |
同一个 getaddrinfo 调用,同时返回两代地址:而调用它的应用代码一行都不用改。
这就是「窄腰」在实践中的样子——你写的程序既能在 IPv4 上跑,也能在 IPv6 上跑,
因为「选哪个地址」这件事交给了系统。
这里有个容易被忽略的细节:
getaddrinfo 一个函数干三件事——查 DNS、挑协议、填好可以直接 connect 的地址结构。
所以现代程序很少自己拼 sockaddr,这件事交给系统,才能同时兼容两代协议。
反过来说,如果程序自己拼了 IPv4 的结构,换到 IPv6 就得改代码——这就是「绕过窄腰」的代价。
四、动手 Demo:同一个域名,两套地址
查同一个域名,看它同时给出几代地址。 关键是「应用代码一行没改」。
import socket
infos = socket.getaddrinfo('www.python.org', 443,
proto=socket.IPPROTO_TCP)
seen = set()
for fam, _t, _p, _c, sa in infos:
if (fam, sa[0]) in seen:
continue
seen.add((fam, sa[0]))
print('%-6s %s' % ('IPv6' if fam == socket.AF_INET6 else 'IPv4',
sa[0]))
实跑输出:
--------------------------------------------------------------------
同一个域名,两套地址
--------------------------------------------------------------------
**「互联网 = TCP/IP 的网络」这句话,用一次解析就能验证。**下面查同一个域名,
看它同时给出几代地址。
地址族 地址
------------------------------
IPv6 2a04:4e42::223
IPv6 2a04:4e42:200::223
IPv6 2a04:4e42:400::223
IPv6 2a04:4e42:600::223
IPv4 151.101.0.223
IPv4 151.101.192.223
IPv4 151.101.128.223
IPv4 151.101.64.223
**同一个 `getaddrinfo` 调用,同时返回 IPv4 与 IPv6 地址**:**而调用它的应用代码一行都不用改。**
**这就是「换掉网络层,传输层与应用层不动」的实证。**
**注意这里 `getaddrinfo` 一个函数就干了三件事**:
**查 DNS、挑协议、填好可以直接 `connect` 的地址结构。**
**所以现代程序很少自己拼 `sockaddr`**——**这件事交给系统,才能同时兼容两代协议。**
IPv6 四条、IPv4 四条:同一个域名,两代地址各给了四个,
这是 CDN 的常见做法(多个节点、多个地址)。
注意顺序是先 IPv6 后 IPv4:getaddrinfo 默认把 IPv6 排在前面,
系统会优先尝试 IPv6,失败了再退回 IPv4。
这个「先六后四」的行为叫 Happy Eyeballs,目的是避免「IPv6 不通时卡住很久」。
这段代码一行 IPv4/IPv6 的判断都没有:它只是把系统给的地址列出来。
真正写客户端时,你连这个循环都不用写——直接把 getaddrinfo 的结果喂给 connect 就行。
30 秒实验
- 把域名换成
www.qq.com,看返回几代地址、各几条。 - 用
socket.AF_INET强制只查 IPv4,看结果差多少。 - 想一下:如果一个程序写死了
AF_INET,换到纯 IPv6 网络会怎样?
常见误区
- 以为「互联网属于某个组织」。 它没有主体,是一堆网络自愿互联的结果。
- 以为 TCP/IP 是「互联网公司的协议」。 它是 IETF 维护的公开标准,谁都能实现。
- 以为「窄腰」只是比喻。 它是结构约束:新介质只要能承载 IP,上面所有应用立刻可用。
自测三问(点开对答案)
1. 互联网与 TCP/IP 是什么关系? —— **「都用」的关系,不是「属于」**:当足够多的网络都用同一套协议互联时,它们合起来就叫互联网。 2. 「窄腰」指什么?好处和代价各是什么? —— **指 IP 是唯一的必经之路**。好处是上下两头能自由生长; 代价是 IP 本身极难改(IPv4 地址耗尽只能靠 NAT 撑着)。 3. 为什么应用代码换 IPv4/IPv6 不用改? —— **因为选地址这件事交给了 `getaddrinfo`**:它一次返回两代地址,程序照着连就行。下一节讲互联网的整体结构:谁连谁。
- ☐ (本节完,下一节 2.3.3 互联网的结构)