刚拿到 192.168.10.0/26 这种写法,第一反应往往是这网段到底能塞几台机器。结论可以一句话给出:可用主机数等于 2 的(32 减去前缀长度)次方再减 2,/26 的主机位是 6 位,2^6 − 2 = 62 台。做网段规划时,这套换算只需要三步——先把前缀长度换成点分十进制掩码,再算出网络号与广播地址,最后用反查规则验一遍。步骤走完,掩码、网段边界、可用地址区间就都出来了。
准备:掩码位数与主机位数的对应关系
掩码位数就是网络位的个数,主机位数等于 32 减去这个数,两者一一对应,没有第三种可能。IPv4 地址一共 32 位,掩码从左往右连续排 1,1 的数量就是前缀长度,剩下的位数留给主机。理解这一层,后面所有公式都是顺推。
常见翻车点是把方向记反:前缀长度数字越大,网段越小。/24 有 8 位主机位,能装 254 台;/26 只剩 6 位主机位,只能装 62 台。有人看到 26 比 24 大,就以为网段更大,划完发现地址不够用,只能返工重划,连带着 DHCP 地址池和防火墙策略一起改。
横向展开对比几个常用前缀,主机位每减 1 位,可用地址就少一半:
| 前缀长度 | 主机位数 | 点分十进制掩码 | 总地址数 | 可用主机数 |
|---|---|---|---|---|
| /24 | 8 | 255.255.255.0 | 256 | 254 |
| /25 | 7 | 255.255.255.128 | 128 | 126 |
| /26 | 6 | 255.255.255.192 | 64 | 62 |
| /27 | 5 | 255.255.255.224 | 32 | 30 |
| /28 | 4 | 255.255.255.240 | 16 | 14 |
| /29 | 3 | 255.255.255.248 | 8 | 6 |
| /30 | 2 | 255.255.255.252 | 4 | 2 |
这张表建议直接抄进规划文档。真正的取舍落在 /30 与 /31 之间:/30 给两台路由器之间的点对点链路留出 2 个可用地址,通用性好;/31 按 RFC 3021 把两个地址都当主机地址用,省掉一半地址空间,代价是两端设备都要支持这种写法,老设备上会配不通。
把两个容易记混的前缀并排看,差异集中在几个维度上:
| 维度 | /24 | /26 | 结论 |
|---|---|---|---|
| 主机位数 | 8 | 6 | 前缀每加 1 位,主机位减 1 |
| 掩码末字节 | 0 | 192 | 从 128 起按 128、64、32 累加 |
| 子网步长 | 256 − 0 = 256 | 256 − 192 = 64 | 步长等于每个子网块的地址数 |
| 可用主机数 | 254 | 62 | 均为总地址数减去保留的两个 |
| 典型用途 | 单一办公网段 | 按部门或业务切分 | 需要隔离时选更长的前缀 |
两个前缀的可用地址数相差数倍,配置工作量却几乎一样,所以隔离需求一出现,往下切分通常比在同一网段里做策略更省事。
执行:把前缀长度换成点分十进制掩码
换算方法只有一句话:从左往右写满前缀长度个 1,其余补 0,再按每 8 位一组转成十进制。/26 就是 26 个 1 加 6 个 0,切成四段是 11111111.11111111.11111111.11000000,逐段加权得到 255.255.255.192。
具体操作按下面五步走:
- 写出 32 位二进制,前 N 位填 1,其余填 0。
- 按 8 位一组,从左到右切成四段。
- 每段按 128、64、32、16、8、4、2、1 加权求和。
- 用点号连接四段,得到点分十进制掩码。
- 记下末段的值,后面算子网步长要用。
末段值的累加规律
末段的值不是随便来的,它是 128 之后的累加:/25 是 128,/26 是 128 + 64 = 192,/27 是 192 + 32 = 224。记不住表的时候,按这个累加规律现推,比翻文档快得多,也不容易记混。
让函数一次算清整张表
下面这段代码把上面五步封成函数,输入前缀长度,直接输出掩码与可用地址数:
def prefix_to_mask(prefix: int) -> str:
"""把 CIDR 前缀长度转成点分十进制掩码。"""
if not 0 <= prefix <= 32:
raise ValueError("前缀长度必须在 0 到 32 之间")
bits = "1" * prefix + "0" * (32 - prefix)
return ".".join(str(int(bits[i:i + 8], 2)) for i in range(0, 32, 8))
def usable_hosts(prefix: int) -> int:
"""可用主机数 = 2^主机位 - 2,/31 与 /32 单独处理。"""
host_bits = 32 - prefix
if prefix == 32:
return 1
if prefix == 31:
return 2
return 2 ** host_bits - 2
for p in (24, 25, 26, 27, 28, 29, 30, 31, 32):
print(f"/{p:<2} {prefix_to_mask(p):<16} 可用 {usable_hosts(p)}")
注意最后两行的分支判断:前缀到 31 和 32 时公式不再减 2,直接返回 2 和 1。漏掉这个判断,脚本会把 /31 点对点链路算成 0 个可用地址,规划时白白浪费一整段地址。
执行:算网络号、广播地址与可用主机数
网络号由 IP 与掩码按位做与运算得到,广播地址是把主机位全部置 1 的结果,可用主机数就是这两个地址之间、除它们自身以外的地址个数。三步是递进关系,前一步错了后面全错。
以 192.168.10.66/26 为例,操作顺序如下:
- 由前缀 26 得出子网步长,256 − 192 = 64。
- 用末位 66 除以 64,得商 1,说明落在第 2 个地址块。
- 网络号末字节为 64,完整网络号是 192.168.10.64。
- 广播地址末字节为 64 + 64 − 1 = 127,即 192.168.10.127。
- 可用区间是 192.168.10.65 到 192.168.10.126,共 62 个。
子网步长这个中间量值得单独记牢:它等于 256 减去掩码末字节的值,也等于每个子网块包含的地址总数。/26 的步长是 64,整段地址的块起点就是 0、64、128、192,末位 66 落进 64 那一块,不用转二进制也能判断归属。
手工推几个网段还行,网段一多就该交给脚本。下面这段用标准库一次性输出网段的整套参数,顺带判断某个 IP 属于哪个子网:
import ipaddress
net = ipaddress.IPv4Network("192.168.10.0/26")
print("网络号 ", net.network_address)
print("广播地址 ", net.broadcast_address)
print("掩码 ", net.netmask)
print("可用主机数", net.num_addresses - 2)
print("可用区间 ", f"{list(net.hosts())[0]} - {list(net.hosts())[-1]}")
for cidr in ("192.168.10.0/26", "192.168.10.64/26", "192.168.10.128/26"):
sub = ipaddress.IPv4Network(cidr)
print(cidr, "->", ipaddress.IPv4Address("192.168.10.66") in sub)
标准库的好处是把边界情况一起处理掉了,网络号和广播地址不会被误当成可用地址。需要留意的一点是,构造 IPv4Network 时默认要求主机位为 0,直接写 192.168.10.66/26 会抛异常,得加 strict=False 才会按掩码截断到网络号。
验证:三条反查规则确认结果没算错
验证只看三处:网络号末字节是不是步长的整数倍、广播地址是不是下一块起点减一、可用地址数是不是等于 2 的主机位次方减 2。三条都对上,结果基本可以放心用。
按顺序核对:
- 用网络号末字节除以步长,余数为 0 才算通过。
- 用网络号加步长再减 1,看是否等于广播地址。
- 用广播地址减网络号再减 1,看可用数是否吻合。
- 把网关地址放进可用区间内,避开首末两个地址。
- 用 ping 确认首末两个地址都不通,说明边界划分正确。
网关与首末地址的分配约定
第 4 步最容易被跳过。网关习惯取第一个可用地址,也就是网络号加一,DHCP 地址池从网关之后开始分配,排查地址冲突时一眼就能定位是哪一段。至于 /32,它表示单个主机地址,多用于环回口和主机路由,不参与子网划分,别把它当成只挂一台机器的普通网段去配网关。
到这里,从二进制掩码到可用主机数的整条换算链路就走完了。步骤不多,但每一步都建议用反查规则兜一遍,网段规划出错后返工的成本,远高于多算两遍。
常见问题(FAQ)
Q1:/26 网段到底能接多少台设备?
62 台。总地址 64 个,扣掉网络号和广播地址各一个,剩下的才能分配给设备。
Q2:为什么可用主机数要减 2?
首地址是网络号,末地址是广播地址,两者都不能配给主机,所以要从总数里减掉。
Q3:/31 和 /32 能不能当普通网段用?
不能。两者属于点对点链路与单主机路由场景,没有网络号和广播地址的分配概念。