Old-School Networking / 2026 ・ No.04
古法网络入门
第4讲 IP 地址 ── 32 位的地址与“/24”,DHCP,还有 IPv6
发布
第 3 讲的 MAC 地址是“到相邻设备”的收件人。从这一讲开始进入第 3 层,网络层。
前半讲 IP 地址本身。10.0.1.10 有多少位?“/24”表示什么?把掩码弄错一个会发生什么?我们实际弄错来确认。
后半讲获取地址的机制(DHCP)、地址不够用的故事,以及 IPv6。路由器如何指路,留到下一讲。
地址这一层
新井“/24”的意思是作业吧,我查了!……是子网掩码的,那个,什么。
古井对了一半。那如果写错成 /16,申请会怎样?
新井诶,只是范围大了一点,应该也能送到吧?
古井试试看。要犯错,在练习网络里犯最便宜。
全 12 讲路线图(当前位置:第 4 讲)
- IP 地址的构成 ── 32 位,网络号和机器号,/24 与掩码
- 发送前的判断 ── 对方在同一网络吗?弄错会怎样(实测)
- 特殊地址与 DHCP ── 私有、127、169.254。获取地址的四次往来(实测)
- 地址耗尽与 IPv6 ── 2011 年库存耗尽的故事,以及 128 位的地址
IP 地址是 32 位
第 3 讲的 MAC 地址是“到相邻设备”的收件人,每经过一台路由器就被换掉。相对地,IP 地址是到最终对方的地址,途中不会改变。
IPv4 地址是 32 位(4 字节)。每 8 位一段分成 4 段,每段写成 0〜255 的十进制,再用“.”连起来,就是熟悉的 10.0.1.10。
10.0.1.10 就是 32 个 0 和 1
地址分成两部分。前面是网络号(哪个城镇),后面是机器号(几号门牌)。表示在哪里分开的就是“/24”这个数字,意思是从前面数 24 位是网络号。
# 第 1 讲电脑的地址
$ ip -4 addr show eth0
inet 10.0.1.10/24 scope global eth0
# 写成二进制(/24=前 24 位是网络号,剩下 8 位是机器号)
address 00001010.00000000.00000001.00001010 10.0.1.10
mask 11111111.11111111.11111111.00000000 255.255.255.0
# 地址与掩码做 AND(两边都是 1 的位才是 1)=网络号
network 00001010.00000000.00000001.00000000 10.0.1.0
“/”后的数字与掩码
/24 和“前 24 位是 1、其余是 0”的 32 位掩码表示同一件事。写成十进制是 255.255.255.0。以前通常写成掩码的形式,现在常用简短的“/24”(CIDR 表示法)。
“/”后的数字越大,网络越小
/24 的网络有 256 个地址,但能分配给机器的是 254 个。因为第一个(10.0.1.0)保留为表示网络本身的编号,最后一个(10.0.1.255)保留为发给该网络所有人的编号。/30 的 4 个地址里能用 2 个,常用于两台路由器之间用一根线相连。
“/24”=前 24 位是网络号=掩码 255.255.255.0。数字每增加 1,网络就缩小一半。
同一网络,还是外面
/24 真正起作用的是发送前的判断。电脑在发送数据包前,会用自己的掩码截取对方地址和自己的地址进行比较。相同,对方就在同一网络,用 ARP 询问对方的 MAC 直接发送。不同,就是外面,交给路由器(默认网关)。
发送前的岔路口
回到开头的问题。在第 1 讲的练习网络中,把新井电脑的地址分别设为正确的 10.0.1.10/24 和错误的 10.0.1.10/16,向路由器另一侧的服务器(10.0.2.20)发 ping。
# 正确的 /24:10.0.2.20 是“外面的”,所以经由路由器(10.0.1.1)发出
$ ip addr add 10.0.1.10/24 dev eth0
$ ip route get 10.0.2.20
10.0.2.20 via 10.0.1.1 dev eth0 src 10.0.1.10 uid 0
$ ping -c 3 10.0.2.20
3 packets transmitted, 3 received, 0% packet loss
# 误设 /16:把 10.0.2.20 也判断为“同一网络”,不经路由器直接发送
$ ip addr add 10.0.1.10/16 dev eth0
$ ip route get 10.0.2.20
10.0.2.20 dev eth0 src 10.0.1.10 uid 0
$ ping -c 3 10.0.2.20
3 packets transmitted, 0 received, 100% packet loss
设成 /16 后,电脑把 10.0.2.20 判断为“同一网络”,想不经过路由器直接发送,于是向所有人询问它的 MAC。可是服务器在路由器的另一边,没人回答。问了 3 次,一个 ping 也没发出去(100% 失败)。掩码不是“大一点、小一点”的问题,而是改变了选路的方式本身。
新井范围大了反而送不到……
古井就像以为“隔壁镇的人也住同一个小区”,在门口一直大声喊。明明交给邮局就能送到。
特殊的地址
IPv4 地址中,有一些保留给特殊用途。放在第一个字节的数轴上是这样的。
具有特殊含义的地址
最重要的是私有地址(10.0.0.0/8、172.16.0.0/12、192.168.0.0/16)。在家里或公司内部,不用向任何人申请就能自由使用。代价是不能直接在互联网上使用。本系列的 10.0.1.10 也是私有地址。家用路由器在出去时把它换成自己的全球地址(NAT),把许多机器藏在一个地址后面(第 5 讲)。
以 127 开头的地址是自己。127.0.0.1 最有名,但因为是 /8,只要以 127 开头就都是自己。
# 以 127 开头的地址,全都是“自己”
$ ping -c 1 127.42.42.42
64 bytes from 127.42.42.42: icmp_seq=1 ttl=64 time=0.285 ms
$ ip addr show lo
inet 127.0.0.1/8 scope host lo
如果自己的电脑上出现了以 169.254 开头的地址,说明没能从 DHCP 获取地址(见下一章)。100.64.0.0/10 是运营商在用户之间共享用的地址,Tailscale 那篇文章里见到的 100.x.y.z 也在这个范围内。
DHCP:获取地址
只要连上家里的 Wi-Fi,电脑就会有地址。分配地址的是路由器里的 DHCP 服务器。我给练习网络的路由器加上 DHCP,记录了没有地址的电脑获取地址的过程(封面照片)。
# 在没有地址的电脑上运行 dhclient 的记录(地址通过 DHCP 获取)
$ dhclient -v eth0
DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 3 (xid=0xcc0bcf66)
DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 5 (xid=0xcc0bcf66)
DHCPOFFER of 10.0.1.177 from 10.0.1.1
DHCPREQUEST for 10.0.1.177 on eth0 to 255.255.255.255 port 67 (xid=0x66cf0bcc)
DHCPACK of 10.0.1.177 from 10.0.1.1 (xid=0xcc0bcf66)
bound to 10.0.1.177 -- renewal in 1714 seconds.
# 收到的 ACK 里写着的内容(来自 Wireshark 的详情)
Your (client) IP address: 10.0.1.177
Subnet Mask: 255.255.255.0
Router: 10.0.1.1
Domain Name Server: 10.0.1.1
IP Address Lease Time: 1 hour (3600)
Renewal Time Value: 30 minutes (1800)
实测:确定地址前的四次往来(以及等待时间)
往来是“Discover(请给我)→ Offer(这个怎么样?)→ Request(我要这个)→ ACK(给你)”四个。没有地址的电脑既不知道自己的地址也不知道对方的,所以用源 0.0.0.0、目的 255.255.255.255(发给所有人)来喊。
有意思的是,确定地址花了约 3 秒。路由器在分配 10.0.1.177 之前,用 ARP 确认了 3 次有没有机器在用这个地址。其间电脑以为没有回应,又发了一次 Discover,所以收到了 2 个 Offer。
得到的地址有期限(租约)。这次是 1 小时,过了一半的 30 分钟(实际的 dhclient 加了随机偏差,是 1,714 秒)就会请求“续租”。电脑合着盖子让租约过期的话,地址可能会分给别的机器。
地址不够用
32 位能做出的地址是 232=约 43 亿个。比地球人口还少,而且还有特殊地址,以及早年的大块分配。
IP 地址年表
全球地址总管 IANA 的库存在 2011 年 2 月 3 日耗尽。包括日本在内的亚太地区 APNIC,也在同年 4 月 15 日结束了常规分配。互联网之所以还在运转,是因为家庭和公司使用私有地址和 NAT,让许多机器共用一个全球地址。而根本的解决方案是 IPv6。
IPv6
IPv6 地址是 128 位。能做出的数量是 2128,不是 IPv4 的 4 倍,而是 296 倍。因为很长,所以每 16 位一组分成 8 组,用十六进制书写,并把连续的 0 缩写。
IPv6 地址的形式
写这篇文章用的云端 Linux 没有 IPv6 功能,所以这里用 Python 的 ipaddress 计算来确认。
>>> import ipaddress
# 连续的 0 缩写成 ::,开头的 0 省略
>>> ipaddress.ip_address('2001:0db8:0000:0000:0000:0000:0000:0001').compressed
'2001:db8::1'
# 地址的数量
>>> 2 ** 128
340282366920938463463374607431768211456
>>> 2 ** 32
4294967296
# 用第 3 讲的 MAC 生成的链路本地地址(EUI-64:插入 ff:fe,翻转本地位)
>>> def eui64(mac):
... b = bytes.fromhex(mac.replace(':', ''))
... iid = bytes([b[0] ^ 0x02]) + b[1:3] + b'\xff\xfe' + b[3:]
... return 'fe80::' + ':'.join(iid[i:i+2].hex() for i in range(0, 8, 2))
...
>>> ipaddress.ip_address(eui64('02:00:00:00:01:10'))
IPv6Address('fe80::ff:fe00:110')
在 IPv6 中,机器可以自己生成地址。前 64 位是路由器告知的网络号,后 64 位是自己生成的编号。以前是用第 3 讲的 MAC 地址生成的(上面的 EUI-64,第 3 讲的本地位在这里被翻转),但那样机器会被追踪,所以现在的操作系统通常使用随机编号。以 fe80:: 开头的地址是只在同一网络内使用的链路本地地址,IPv6 设备一定都有。
普及虽然缓慢,但稳步前进。访问 Google 的连接中使用 IPv6 的比例,在 2026 年 4 月首次达到约一半。现在很多家庭里 IPv4 和 IPv6 同时运行(双栈),哪个能用就选哪个。做服务器的一方,别忘了确认 IPv6 也在监听(第 7 讲)。
在自己的电脑上确认
| 想查什么 | Mac | Windows | Linux |
|---|---|---|---|
| 自己的地址和掩码 | ifconfig | ipconfig | ip addr |
| 默认网关 | netstat -rn | route print | ip route |
| DHCP 得到的内容 | ipconfig getpacket en0 | ipconfig /all | nmcli -f DHCP4 device show |
| IPv6 能否到达 | ping6 | ping -6 | ping -6 |
在家里的电脑上看 ipconfig 或 ifconfig,通常会看到以 192.168 或 10 开头的地址(私有)和以 fe80:: 开头的地址。如果是以 169.254 开头,说明没能从 DHCP 获取地址。先检查路由器的电源和网线(第 2 讲)。
结 — 一页总结与下一讲
- IP 地址是到最终对方的地址。IPv4 是 32 位,10.0.1.10 就是 0a 00 01 0a 这 4 个字节。
- “/24”表示前 24 位是网络号=掩码 255.255.255.0。/24 有 256 个地址,可用 254 个。
- 发送前用掩码截取后比较,相同就直接发,不同就交给路由器。
- 误设成 /16,会一直询问路由器另一边对方的 MAC,ping 100% 失败。
- 私有(10、172.16、192.168),自己(127),DHCP 失败的标志(169.254)。
- DHCP 是 Discover、Offer、Request、ACK。实测因为路由器的确认,花了约 3 秒。租期 1 小时。
- IPv4 库存在 2011 年耗尽。IPv6 是 128 位,访问 Google 的连接约一半已是 IPv6。
新井知道是“外面”就交给路由器……那路由器又是怎么决定下一站的?
古井路由器有一张指路的表。下一讲讲这张表、利用 TTL 查路径的 traceroute,以及家用路由器的真面目。
参考
- RFC 791 — Internet Protocol (1981)
- RFC 4632 — Classless Inter-domain Routing (CIDR)
- RFC 1918 — Address Allocation for Private Internets
- RFC 6598 — Shared Address Space (100.64.0.0/10)
- RFC 3927 — Link-Local IPv4 Addresses (169.254.0.0/16)
- RFC 2131 — Dynamic Host Configuration Protocol
- JPNIC — IPv4 address pool ran out in the Asia Pacific region
- RFC 8200 — Internet Protocol, Version 6 (IPv6) Specification(RFC 2460 の後継)
- RFC 4291 — IP Version 6 Addressing Architecture
- RFC 8981 — Temporary Address Extensions for SLAAC in IPv6
- APNIC Blog — Google hits 50% IPv6 (2026-04-28)
- Python — ipaddress
记录来自笔者在云端 Linux(Ubuntu 24.04)上用网络命名空间搭建的练习网络,于 2026 年 10 月 24 日抓取。DHCP 使用路由器角色的 dnsmasq(租期 1 小时)和 dhclient(isc-dhcp-client 4.4.3),其余与第 1 讲相同。表中的数字都是从这些记录和当时命令的输出读出的实际数值。该环境的内核没有 IPv6,所以 IPv6 的例子是用 Python 的 ipaddress 计算的。地址耗尽的日期依据 JPNIC,IPv6 的比例依据 APNIC Blog(Google 的统计,2026 年 4 月)。登场人物均为虚构。
古法网络入门 第4讲 — IP 地址 / 2026.10