IP 子网划分是每个开发者和运维工程师都绕不开的基础知识。无论是配置 AWS VPC、规划公司内网,还是排查两台主机互不通的问题,子网计算都会用到。这篇文章讲清楚 CIDR 表示法、子网掩码和网络参数的计算方法,配合在线工具可以直接得出结果。

什么是子网划分?

子网(Subnet)是对 IP 网络进行的逻辑分段。把一个大的 IP 地址块分成若干小段,好处有:

  • 隔离 — 子网内的流量不出子网,跨子网流量经网关转发
  • 安全 — 防火墙和 ACL 可以在子网边界执行策略
  • 效率 — 缩小广播域,减少不必要的广播流量
  • 地址管理 — 按需分配,避免浪费

CIDR 表示法解析

CIDR(无类别域间路由)把 IP 地址和路由前缀写在一起:

192.168.1.0/24
│           │
└─ 网络地址  └─ 前缀长度(位数)

/24 表示前 24 位是网络部分,剩余 8 位是主机部分。这决定了子网内能有多少台主机。

前缀长度与主机数对照

CIDR子网掩码可用主机数常见用途
/8255.0.0.016,777,214大型 ISP 地址块
/16255.255.0.065,534企业内网
/24255.255.255.0254典型办公室局域网
/25255.255.255.128126把 /24 对半分
/26255.255.255.19262小型网段
/27255.255.255.22430VLAN 网段
/28255.255.255.24014小团队
/29255.255.255.2486点对点链路
/30255.255.255.2522路由器互联
/31255.255.255.2540(特殊)点对点(RFC 3021)
/32255.255.255.2551主机路由

可用主机数 = 2^(32 - 前缀长度) - 2(减去网络地址和广播地址)

关键子网参数

192.168.10.64/26 为例:

参数计算方法
网络地址192.168.10.64IP 与子网掩码做 AND 运算
子网掩码255.255.255.19226 个 1,6 个 0(二进制)
广播地址192.168.10.127主机位全置 1
第一个可用主机192.168.10.65网络地址 + 1
最后一个可用主机192.168.10.126广播地址 - 1
可用主机数622^6 - 2
通配符掩码0.0.0.63子网掩码取反

二进制分析

IP:      11000000.10101000.00001010.01000000  (192.168.10.64)
掩码:    11111111.11111111.11111111.11000000  (255.255.255.192)
网络:    11000000.10101000.00001010.01000000  (192.168.10.64)
广播:    11000000.10101000.00001010.01111111  (192.168.10.127)

前 26 位固定(网络部分),后 6 位变化(主机空间)。

子网划分实践

AWS VPC 设计

AWS 需要为每个 VPC 和子网指定 CIDR 块,典型三层架构:

VPC:        10.0.0.0/16    (65,536 个地址)
├─ 公有子网: 10.0.1.0/24   (254 个可用 — 面向互联网)
├─ 私有子网: 10.0.2.0/24   (254 个可用 — 应用层)
└─ 数据库:   10.0.3.0/24   (254 个可用 — RDS 隔离)

AWS 每个子网保留 5 个地址(前 4 个 + 广播),每个 /24 实际可用 251 个。

Kubernetes Pod CIDR

K8s 集群要求节点、Pod 和 Service 的 CIDR 不重叠:

# kubeadm 配置片段
networking:
  podSubnet: 10.244.0.0/16      # Pod IP
  serviceSubnet: 10.96.0.0/12   # ClusterIP Service

确保这些地址段不与节点网络或 VPC CIDR 重叠。

Docker 自定义网络

# 创建自定义 bridge 网络
docker network create \
  --driver bridge \
  --subnet 172.20.0.0/24 \
  --gateway 172.20.0.1 \
  my-network

docker network lsip route 检查是否与现有网络重叠。

代码计算子网参数

Python ipaddress 模块

Python 标准库已内置完整子网计算功能:

import ipaddress

net = ipaddress.IPv4Network('192.168.10.64/26', strict=False)

print(net.network_address)    # 192.168.10.64
print(net.broadcast_address)  # 192.168.10.127
print(net.netmask)            # 255.255.255.192
print(net.num_addresses)      # 64(含网络和广播地址)
print(list(net.hosts())[:3])  # [192.168.10.65, .66, .67]

# 检查 IP 是否在子网内
ip = ipaddress.IPv4Address('192.168.10.80')
print(ip in net)  # True

# 划分为 /28 子网
for subnet in net.subnets(new_prefix=28):
    print(subnet)
# 192.168.10.64/28
# 192.168.10.80/28
# 192.168.10.96/28
# 192.168.10.112/28

JavaScript

// 不依赖第三方库的简单实现
function subnetInfo(cidr) {
  const [ip, prefix] = cidr.split('/');
  const prefixLen = parseInt(prefix);
  
  const ipParts = ip.split('.').map(Number);
  const ipInt = ipParts.reduce((acc, oct) => (acc << 8) | oct, 0) >>> 0;
  
  const maskInt = prefixLen === 0 ? 0 : (~0 << (32 - prefixLen)) >>> 0;
  const networkInt = (ipInt & maskInt) >>> 0;
  const broadcastInt = (networkInt | ~maskInt) >>> 0;
  
  const toIP = n => [24, 16, 8, 0].map(s => (n >> s) & 0xFF).join('.');
  
  return {
    network: toIP(networkInt),
    broadcast: toIP(broadcastInt),
    mask: toIP(maskInt),
    firstHost: toIP(networkInt + 1),
    lastHost: toIP(broadcastInt - 1),
    usableHosts: Math.pow(2, 32 - prefixLen) - 2,
  };
}

console.log(subnetInfo('192.168.10.64/26'));
// { network: '192.168.10.64', broadcast: '192.168.10.127', ... }

Go net

import "net"

_, ipNet, err := net.ParseCIDR("192.168.10.64/26")
if err != nil {
    panic(err)
}

fmt.Println(ipNet.IP)   // 192.168.10.64(网络地址)
fmt.Println(ipNet.Mask) // ffffffc0(十六进制掩码)

// 检查 IP 是否在子网内
testIP := net.ParseIP("192.168.10.80")
fmt.Println(ipNet.Contains(testIP))  // true

私有 IP 地址范围

这些范围保留给内部使用(RFC 1918):

范围CIDR地址数量
10.0.0.0 – 10.255.255.25510.0.0.0/8约 1,677 万
172.16.0.0 – 172.31.255.255172.16.0.0/12约 104 万
192.168.0.0 – 192.168.255.255192.168.0.0/1665,536

内部基础设施始终用私有地址段。公有 IP 在互联网上路由,私有 IP 不会。

常见子网计算错误

忘记保留地址:每个子网损失 2 个地址(网络地址 + 广播地址)。一个 /29 共 8 个地址,只有 6 个可用。

子网地址重叠10.0.1.0/2410.0.0.0/16 重叠——/24 里的每个地址也属于 /16,导致路由歧义。

主机范围差一:第一个可用主机是网络地址 +1,最后一个是广播地址 -1。/24 的主机范围是 .1.254,而非 .0.255

CIDR 对齐:子网起始地址必须对齐到前缀长度对应的边界。10.0.0.1/24 不是合法 CIDR(主机位非零),正确写法是 10.0.0.0/24

使用在线 IP 子网计算器

使用 ZeroTool IP 子网计算器 →

输入任意 IPv4 地址和 CIDR 前缀长度,立即获得:

  • 网络地址和广播地址
  • 子网掩码和通配符掩码
  • 第一个和最后一个可用主机地址
  • 总地址数和可用主机数
  • 所有字段的二进制表示

免注册,无广告,浏览器本地运算。适合 VPC 规划、网络排障和架构评审时快速确认子网参数。

在线计算 IPv4 子网 →