模块三 · 网络层:数据平面
IP 地址与子网划分
你会看 IP 地址,但说不清后面那个 /24 或 255.255.255.0 到底在干什么。
本章要解决的问题:你会看 IP 地址,但说不清后面那个 /24 或 255.255.255.0 到底在干什么。
本章的证据来源:captures/snapshot-20261012-220243.md(本机快照)
和 captures/lab_subnet_verify_output.txt(代码验证输出)。
先从一个例子理解概念
电脑看到目标地址,要先判断“对方在我直接连接的网络上吗,还是要先交给网关”。子网掩码就是这个判断的一部分。
网络层的地址:IPv4
IPv4是IP的一种版本,地址常写成四段数字,例如192.168.1.10。每段表示一个字节,整条地址共32个二进制位。
地址怎样分成两部分:网络前缀与主机部分
同一子网的地址具有共同的前面一段,叫网络前缀;后面的部分区分该范围中的地址。不是看起来前三段相同就永远同网段。
从哪一位分开:掩码与斜杠写法
子网掩码规定哪些位参与网络前缀判断。/24表示前24位是前缀,剩下8位在该范围内变化;对应掩码255.255.255.0。先理解“分界位置”,再算地址数量。
怎样比较:按位与
按位与(AND)逐位计算,两个输入都是1才得到1。IP与掩码做这个运算,可保留网络位并清零主机位;比较得到的前缀才是后面的计算依据。
下面再用这些概念看原理、命令和结果。规范与官方资料列在本章末尾,类比只帮助理解,不代替协议规则。
掩码只干一件事:把 32 位切成两段
一个 IPv4 地址是 32 位。它被掩码切成两段:
192 . 168 . 31 . 215
11000000 10101000 00011111 11010111 ← 32 位
└──────┬───────┘ └──────┬───────┘
网络号部分 主机号部分掩码告诉你从第几位切。/24 表示前 24 位是网络号,后 8 位是主机号。
判断两台主机是否在同一个网段,就是把各自的 IP 和掩码做按位与,比较结果:
192.168.31.215 AND 255.255.255.0 = 192.168.31.0
192.168.31.1 AND 255.255.255.0 = 192.168.31.0 ← 相同 → 同网段
192.168.32.10 AND 255.255.255.0 = 192.168.32.0 ← 不同 → 要过网关就这么多。「子网划分」听起来玄,本质就是用掩码决定切在哪儿, 而切在哪儿决定了「谁能直接对话、谁必须经过路由器」。
为什么要有这个东西:如果全世界的设备都在一个网段里,每台机器发一个广播包, 全球所有设备都要处理一次。IP子网划分的是三层地址范围;二层广播域由桥接/VLAN等决定。通常让两者对应,单独改掩码不会把交换机广播域切开。
换算表(背几个就够)
| 前缀 | 子网掩码 | 总地址数 | 可用主机数 | 说明 |
|---|---|---|---|---|
| /30 | 255.255.255.252 | 4 | 2 | 点到点链路,刚好两个端点 |
| /29 | 255.255.255.248 | 8 | 6 | |
| /28 | 255.255.255.240 | 16 | 14 | |
| /27 | 255.255.255.224 | 32 | 30 | |
| /26 | 255.255.255.192 | 64 | 62 | |
| /25 | 255.255.255.128 | 128 | 126 | |
| /24 | 255.255.255.0 | 256 | 254 | 家用网络最常见的 |
| /23 | 255.255.254.0 | 512 | 510 | |
| /22 | 255.255.252.0 | 1024 | 1022 | |
| /21 | 255.255.248.0 | 2048 | 2046 | |
| /20 | 255.255.240.0 | 4096 | 4094 | 本机 WSL 用的这个 |
| /16 | 255.255.0.0 | 65536 | 65534 | 本机 APIPA 用的这个 |
| /12 | 255.240.0.0 | 1048576 | 1048574 | 私有段 172.16/12 |
| /8 | 255.0.0.0 | 16777216 | 16777214 | 私有段 10/8 |
为什么可用主机数要减 2:每个网段的第一个地址是网络号(标识这个网段本身), 最后一个是广播地址(发给网段内所有主机)。这两个都不能分配给设备。
实测:同一台机器上,四种前缀长度同时存在
先看实测数据(captures/lab_subnet_verify_output.txt 第一部分):
接口 本机地址 前缀 子网掩码 网络号 可用主机数
--------------------------------------------------------------------------
WLAN 192.168.31.215 /24 255.255.255.0 192.168.31.0 254
广播地址 -> 192.168.31.255 可用范围 192.168.31.1 ~ 192.168.31.254
FlClash 198.18.0.1 /30 255.255.255.252 198.18.0.0 2
广播地址 -> 198.18.0.3 可用范围 198.18.0.1 ~ 198.18.0.2
vEthernet WSL 172.30.0.1 /20 255.255.240.0 172.30.0.0 4094
广播地址 -> 172.30.15.255 可用范围 172.30.0.1 ~ 172.30.15.254
蓝牙网络连接 169.254.215.100 /16 255.255.0.0 169.254.0.0 65534
广播地址 -> 169.254.255.255 可用范围 169.254.0.1 ~ 169.254.255.254现在逐个拆开,重点看路由表和 ARP 表怎么印证这些计算。
1.3.1 /24 —— 你的无线网
本机 192.168.31.215/24 → 网络号 192.168.31.0,广播 192.168.31.255
可用范围 192.168.31.1 ~ 192.168.31.254(254 个)打开 captures/snapshot-20261012-220243.md 的第 5 节(完整路由表),能找到三条:
192.168.31.0/24 0.0.0.0 WLAN Local ← 整个网段是直连的
192.168.31.215/32 0.0.0.0 WLAN Local ← 本机自己的地址
192.168.31.255/32 0.0.0.0 WLAN Local ← 广播地址再看第 6 节(ARP 表):
Interface: 192.168.31.215 --- 0x11
192.168.31.1 a4-39-b3-0b-ab-19 dynamic ← 网关,有真实 MAC
192.168.31.51 e8-51-77-27-5a-9a dynamic ← 局域网里另一台设备
192.168.31.248 fa-aa-ff-92-e6-3f dynamic ← 又一台
192.168.31.255 ff-ff-ff-ff-ff-ff static ← 广播地址的"MAC"三件事对上了:
- 计算出的广播地址
192.168.31.255,在路由表里是一条/32主机路由,在 ARP 表里的 MAC 是ff-ff-ff-ff-ff-ff—— 全 1 就是二层广播地址。 - 网关
192.168.31.1有真实 MAC,说明它在同一网段,可以直接用 ARP 找到它。 - 你的机器是
.215,所以.1~.214和.216~.254才是"邻居"。
→ 掩码算出来的范围,和系统实际行为完全一致。这就是验证的方法。
1.3.2 /30 —— 只有两个可用地址的网段
FlClash 198.18.0.1/30 → 网络号 198.18.0.0,广播 198.18.0.3
可用只有两个:198.18.0.1 和 198.18.0.2路由表第 5 节:
198.18.0.0/30 0.0.0.0 FlClash Local
198.18.0.1/32 0.0.0.0 FlClash Local
198.18.0.3/32 0.0.0.0 FlClash LocalARP 表:
Interface: 198.18.0.1 --- 0x10
198.18.0.1 dynamic
198.18.0.2 dynamic
198.18.0.3 static注意 198.18.0.x 这几行的 MAC 地址是空的。为什么?
因为这是块 TUN 虚拟网卡(代理软件建的),它工作在 IP 层,根本没有二层, 自然没有 MAC 地址。ARP 表里留了几行空记录,是 Windows 协议栈的惯性行为。
/30 的实用意义:常规IPv4子网去掉网络号和广播后恰有两个主机地址。 但它不是无条件的最小可用网段:RFC 3021允许点到点链路使用/31,两端都可用;/32用于单地址配置与主机路由。 这是点到点链路(比如 VPN 隧道)的经典配置。
1.3.3 /20 —— 最容易算错的那个
vEthernet (WSL) 172.30.0.1/20 → 网络号 172.30.0.0,广播 172.30.15.255
可用范围 172.30.0.1 ~ 172.30.15.254(4094 个)关键点:第三段不是 0~255,而是 0~15。
因为 /20 只给了第三段 4 位、第四段 8 位当主机号(4+8=12 位), 而第三段的高 4 位属于网络号。所以第三段每 16 个地址就换一个网段。
验证(lab_subnet_verify_output.txt 第三部分):
172.30.14.213 在网段内,可用
172.30.15.255 在网段内,但它是广播地址(不能给主机用)
172.30.15.254 在网段内,可用
172.30.16.1 在网段外 —— 它属于下一个 /20 网段 172.30.16.0/20ARP 表提供了漂亮的旁证:
Interface: 172.30.0.1 --- 0x22
172.30.14.213 00-15-5d-fb-2f-0a dynamic ← 有真实 MAC,是真主机
172.30.15.255 ff-ff-ff-ff-ff-ff static ← 广播,MAC 全 1.14.213 落在范围内,有真 MAC;.15.255 恰好在范围的最末端,是广播,MAC 全 1。 代码算出来的边界和系统实际行为又对上了。
1.3.4 /16 与 169.254.x.x —— DHCP 失败长什么样
蓝牙网络连接 169.254.215.100/16 → 网络号 169.254.0.0,广播 169.254.255.255169.254.0.0/16 是 RFC 3927 规定的链路本地地址段(APIPA)。 规则很简单:如果一台机器开着 DHCP 但拿不到地址,就自己从这一段里随机挑一个。
本机有 6 个接口是 169.254.x.x:
| 接口 | 地址 |
|---|---|
| 以太网 | 169.254.163.90 |
| 本地连接 | 169.254.114.105 |
| 本地连接* 9 | 169.254.177.27 |
| 本地连接* 10 | 169.254.119.78 |
| Heysocks | 169.254.37.161 |
| 蓝牙网络连接 | 169.254.215.100 |
169.254/16是有效的链路本地地址。 在Windows启用DHCP的接口上,它常提示没有获得DHCP地址;但也可能是配置或历史状态,不能由地址单独确定失败原因,更不能代表其他网卡或IPv6也不能通信。
这也解释了一个常见困惑:为什么这些接口明明没网,却看起来配置齐全? 因为 APIPA 把地址配好了 —— 能通局域网,但不能跨路由器, 而且没有默认网关。看第 3 节,这 6 个接口确实一条默认路由都没贡献。
心算法:块大小(不用计算器)
考试和排障时最实用的一招:
块大小 = 256 - (掩码中"那个关键段"的值)
网络号 = IP 对应段的值 - (该值 mod 块大小)
广播 = 网络号 + 块大小 - 1关键段指掩码里既不是 255 也不是 0 的那一段。掩码全是 255 和 0 时, 关键段就是第一个为 0 的段(块大小 256)。
拿本机三个真实例子走一遍:
① 192.168.31.215/24
掩码 255.255.255.0 → 关键段是第 4 段,值 0 → 块大小 = 256 - 0 = 256
网络号:215 - (215 mod 256) = 215 - 215 = 0 → 192.168.31.0 ✔
广播 :0 + 256 - 1 = 255 → 192.168.31.255 ✔
② 172.30.0.1/20
掩码 255.255.240.0 → 关键段是第 3 段,值 240 → 块大小 = 256 - 240 = 16
网络号:0 - (0 mod 16) = 0 → 172.30.0.0 ✔
广播 :第 3 段 0 + 16 - 1 = 15,第 4 段全体 255 → 172.30.15.255 ✔
③ 198.18.0.1/30
掩码 255.255.255.252 → 关键段第 4 段,值 252 → 块大小 = 256 - 252 = 4
网络号:1 - (1 mod 4) = 1 - 1 = 0 → 198.18.0.0 ✔
广播 :0 + 4 - 1 = 3 → 198.18.0.3 ✔三个都和代码算出来的完全一致。心算完,再用脚本验一遍,这才是可靠的流程。
动手:跑一遍验证脚本
python labs\lab_subnet_verify.py这个脚本做三件事:
- 用
ipaddress模块算出每个接口的网络号、掩码、广播、可用范围 - 拿 ARP 表交叉验证:每个邻居是不是真的落在同一个网段里
- 专门验证
/20的边界断点
第二部分输出(节选):
192.168.31.1 dynamic 网关 同网段=是 普通主机
192.168.31.255 static 广播地址 同网段=是 广播?
198.18.0.3 static 广播地址 同网段=是 广播?
172.30.14.213 dynamic WSL 侧主机 同网段=是 普通主机这一步的意义:手算掩码很容易错,而且错了往往不自知(因为你不会去验证)。 让程序算、再和系统实际行为对照,对不上就说明算错了。
练一练
不看下文,先算这几个,再用脚本验证:
4 题 · 先自己答,再展开对照
10.0.5.77/22的网络号和广播地址?/22→ 掩码 255.255.252.0,关键段第 3 段,块大小 = 256-252 = 4。
网络号:5 - (5 mod 4) = 5 - 1 = 4 → 10.0.4.0;广播 → 第 3 段 4+4-1 = 7,第 4 段 255 → 10.0.7.255。192.168.100.200/26里能放多少台主机?可用范围?/26→ 掩码 255.255.255.192,块大小 = 256-192 = 64。总地址 64 个,可用 62 台。
网络号:200 - (200 mod 64) = 200 - 8 = 192 → 192.168.100.192;广播 → 192+64-1 = 255 →
可用范围 192.168.100.193 ~ 192.168.100.254。判断:
172.16.10.5/21和172.16.15.200/21同网段吗?/21→ 掩码 255.255.248.0,块大小 = 256-248 = 8。10 mod 8 = 2→ 网络号 172.16.8.0;15 mod 8 = 7→ 网络号 172.16.8.0。
同网段(范围是 172.16.8.0 ~ 172.16.15.255)。注意:这里"第三段相同"的直觉会骗人 ——10和15看着不同,但都在8~15这一块里。判断:
192.168.1.10/24和192.168.1.10/25是同一个网段吗?不是。/24的网络号是 192.168.1.0(范围 .0~.255);/25的关键段是第 4 段、
值 128、块大小 128,网络号 = 1.10 的10 mod 128 = 10→ 192.168.1.0,
范围 .0~.127。地址相同但掩码不同 → 可用范围不同 → 广播地址不同(.255 vs .127)。
网络里两边掩码不一致是经典故障源。
常见错误
错误 1:把子网掩码的每一段当成独立数字
255.255.240.0 里的 240 不是"240 台主机"。第三段的块大小是 256-240 = 16, 第三段只能取 0, 16, 32, 48, ...。
错误 2:以为"IP 前三段一样就是同网段"
双方采用相同/24掩码时,前三字节相同即可判断同前缀;相同/20或/22下也不会因此跨子网。反例应是/25或/26:例如192.168.1.10/25与192.168.1.200/25前三字节相同却分属两个子网。 永远按掩码算,别看地址长相。
错误 3:忽略两台主机掩码不一致
同网段判断是双方各自用掩码算。如果 A 是 /24、B 是 /25, A 认为 B 在同网段,B 可能认为 A 需要过网关 —— 通信就会单向失败。 排障时必须两边都查掩码。
错误 4(程序员的坑):字节序
这是本次实测中真实踩到的。想在 PowerShell 里把前缀长度转成掩码:
# 错误写法
$bits = [uint32]([math]::Pow(2,32) - [math]::Pow(2,32 - 30))
([IPAddress]$bits).ToString()
# 输出 252.255.255.255 ← 完全错了,字节序颠倒正确写法:
$bits = [uint32]([math]::Pow(2,32) - [math]::Pow(2, 32 - $prefixLength))
$bytes = [BitConverter]::GetBytes($bits) # 得到小端字节序
[array]::Reverse($bytes) # 翻成网络序
([IPAddress]$bytes).ToString() # /30 -> 255.255.255.252 ✔根因:网络字节序是大端,而 x86 是小端。IPAddress 的数值构造重载 按小端解释,于是 8 位数翻转了。这个坑在写任何协议解析代码时都会遇到 —— IP/TCP/UDP等协议的多字节整数字段按网络字节序;应用载荷的编码由其协议定义,并非所有数据都大端,所有 ntohs / htonl 就是为了处理这件事。
本章小结
| 结论 | 状态 |
|---|---|
| 掩码决定网络号/主机号的分界,判断同网段靠按位与 | 原理 |
| 常规IPv4子网主机数通常为总数减2;/31点到点与/32另论 | 有条件计算 |
| 本机同时存在 /16、/20、/24、/30 四种前缀 | 实测 |
| 掩码算出的网络号/广播,与路由表和 ARP 表完全吻合 | 实测 |
6 个接口处于 169.254/16,说明 DHCP 未成功 | 实测 |
/20 的第三段以 16 为步长,172.30.15.255 是广播 | 实测 |
00-15-5D 属于 Hyper-V | 判断(未查 OUI 库) |
下一章:这些地址要真正通信,还需要 TCP 把连接建起来。 TCP章节记录本地连接状态实验;仅凭状态表无法逐包观察线上握手,真正观察报文需要抓包。
参考资料与适用范围
修订核对日期:2026-10-13。规则按所列协议与实现范围理解;文中的原始命令输出是历史观察,不表示本次重新实测。跨版本、代理/隧道及不同捕获位置需要另行核对。