一句话:子网掩码是一个 32 位的数字,用来把 IP 地址切成两半:前一半是"网络号"(你住哪个小区),后一半是"主机号"(你是小区里的哪一户)。
上一篇讲网关时提到:电脑靠IP + 子网掩码判断目标是否在同一网段,在就直接发,不在就交给网关。这一篇把这个"判断"拆开讲清楚。
一、生活里的例子:电话号码
一个座机号码010-12345678:
010是区号:表示北京12345678是本地号码:北京的哪一部电话
打电话时:
- 区号相同 → 本地通话,直接拨
- 区号不同 → 长途,要经过长途交换局
| 电话 | IP 网络 |
|---|---|
| 区号 | 网络号 |
| 本地号码 | 主机号 |
| "前几位是区号"这条规则 | 子网掩码 |
| 长途交换局 | 网关 |
关键:IP 地址本身不会告诉你"前几位是区号",子网掩码负责说明这一点。
二、子网掩码长什么样
IP 地址和子网掩码都是32 位二进制数,为了好读,写成 4 段十进制。
子网掩码:255.255.255.0 二进制: 11111111.11111111.11111111.00000000 └──────── 24 个 1 ────────┘└ 8 个 0 ┘ 网络号部分 主机号部分规则很简单:
| 位 | 意思 |
|---|---|
| 1 | 这一位属于网络号 |
| 0 | 这一位属于主机号 |
并且1 必须连续地排在前面,0 连续排在后面。所以255.0.255.0是不合法的掩码。
三、CIDR 写法:数一数有几个 1
每次写255.255.255.0太长,于是有了简写:直接写有几个 1。
192.168.1.10 + 255.255.255.0 ↓ 简写为 192.168.1.10/24 ← 24 个 1| 十进制写法 | CIDR | 二进制最后一段 |
|---|---|---|
| 255.0.0.0 | /8 | — |
| 255.255.0.0 | /16 | — |
| 255.255.255.0 | /24 | 00000000 |
| 255.255.255.128 | /25 | 10000000 |
| 255.255.255.192 | /26 | 11000000 |
| 255.255.255.224 | /27 | 11100000 |
| 255.255.255.240 | /28 | 11110000 |
| 255.255.255.248 | /29 | 11111000 |
| 255.255.255.252 | /30 | 11111100 |
| 255.255.255.255 | /32 | 11111111 |
最后一段只可能是这几个数:0、128、192、224、240、248、252、254、255。看到其他数字(比如 255.255.255.100),一定是填错了。
四、核心计算:按位"与"(AND)
电脑判断"是不是同一网段",只做一件事:IP 和掩码按位相与,得到网络地址。
AND 规则:两个都是 1 才得 1。
IP: 192.168.1.10 = 11000000.10101000.00000001.00001010 掩码: 255.255.255.0 = 11111111.11111111.11111111.00000000 ─────────────────────────────────────────────────────────── AND 网络: 192.168.1.0 = 11000000.10101000.00000001.00000000掩码为 1 的位置原样保留,为 0 的位置全部清零。就像用一张"遮罩"盖住后面几位,这就是"掩码"这个名字的由来。
判断是否同网段:两个 IP 分别和掩码相与,结果一样就是同网段。
| 本机 192.168.1.10/24 | 目标 & 掩码 | 网络地址相同? | 怎么发 |
|---|---|---|---|
| 192.168.1.20 | 192.168.1.0 | ✅ | 直接发 |
| 192.168.2.20 | 192.168.2.0 | ❌ | 交给网关 |
| 8.8.8.8 | 8.8.8.0 | ❌ | 交给网关 |
接前面的汇编篇:这在 CPU 里就是一条
and指令再加一条cmp,极快。内核每发一个包都要做这种判断。
五、一个网段能放多少台设备?
主机号有n位,就有2ⁿ个地址,但有两个不能分给设备:
| 地址 | 特点 | 用途 |
|---|---|---|
| 网络地址 | 主机位全是 0 | 代表这个网段本身,如 192.168.1.0 |
| 广播地址 | 主机位全是 1 | 发给全网段所有设备,如 192.168.1.255 |
所以:可用主机数 = 2^(32 − 前缀长度) − 2
| CIDR | 主机位 | 总地址 | 可用主机 | 常见用途 |
|---|---|---|---|---|
| /8 | 24 | 16,777,216 | 16,777,214 | 超大内网(10.0.0.0/8) |
| /16 | 16 | 65,536 | 65,534 | 大型园区、云上 VPC |
| /24 | 8 | 256 | 254 | 家庭、小办公室,最常见 |
| /26 | 6 | 64 | 62 | 一个部门 |
| /28 | 4 | 16 | 14 | 一小组服务器 |
| /30 | 2 | 4 | 2 | 两台路由器之间点对点 |
| /31 | 1 | 2 | 2(特例) | 点对点链路,不需要网络/广播地址 |
| /32 | 0 | 1 | 1 | 表示"就这一台主机",常见于路由表、防火墙规则 |
六、速算技巧:不用写二进制
考试、排查时最常见的问题:“某个 IP 属于哪个网段?范围是多少?”
技巧:块大小 = 256 − 掩码中那段不是 255 也不是 0 的数
例:192.168.1.130/26 的网段范围
1. /26 → 掩码 255.255.255.192 2. 块大小 = 256 − 192 = 64 3. 网段按 64 切:0、64、128、192 4. 130 落在 128 ~ 191 这一块| 项目 | 结果 |
|---|---|
| 网络地址 | 192.168.1.128 |
| 第一个可用 | 192.168.1.129 |
| 最后一个可用 | 192.168.1.190 |
| 广播地址 | 192.168.1.191 |
| 可用主机数 | 62 |
再练一个:10.20.37.5/20
1. /20 → 掩码 255.255.240.0(第三段是 240) 2. 块大小 = 256 − 240 = 16,作用在第三段 3. 第三段按 16 切:0、16、32、48… 4. 37 落在 32 ~ 47结果:网络10.20.32.0,广播10.20.47.255,可用10.20.32.1 ~ 10.20.47.254。
七、划分子网:一块地切成几块
场景:一个小游戏工作室拿到192.168.10.0/24,想分成 4 个互相隔离的网络。
切 4 块需要借 2 位主机位(2² = 4),/24 → /26:
| 子网 | 网段 | 可用范围 | 给谁 |
|---|---|---|---|
| 1 | 192.168.10.0/26 | .1 ~ .62 | 开发人员电脑 |
| 2 | 192.168.10.64/26 | .65 ~ .126 | 测试服务器、打包机 |
| 3 | 192.168.10.128/26 | .129 ~ .190 | 美术、策划 |
| 4 | 192.168.10.192/26 | .193 ~ .254 | 访客 Wi-Fi |
每个子网有自己的网关(通常用第一个可用地址,如 .1、.65、.129、.193),子网之间的通信要经过路由器,可以在路由器上加规则:访客 Wi-Fi 不能访问服务器。
为什么要划分子网?
| 好处 | 说明 |
|---|---|
| 安全隔离 | 访客、开发、服务器分开,出问题不会互相影响 |
| 减少广播 | 广播只在本子网内传,网段越大,广播越吵 |
| 好管理 | 看 IP 就知道是哪类设备 |
| 不浪费地址 | 两台路由器互联只用 /30,不用占掉一整个 /24 |
这又是"架构原则"里那个老道理:划清边界,各管一块。只不过这次是在网络层面。
八、私有地址:家里和公司常用的网段
这些地址只在内网使用,互联网上不路由(要靠上一篇讲的 NAT 出去):
| 范围 | CIDR | 常见场景 |
|---|---|---|
| 10.0.0.0 ~ 10.255.255.255 | 10.0.0.0/8 | 企业、云服务器 |
| 172.16.0.0 ~ 172.31.255.255 | 172.16.0.0/12 | 企业、Docker 默认网络 |
| 192.168.0.0 ~ 192.168.255.255 | 192.168.0.0/16 | 家用路由器 |
| 100.64.0.0 ~ 100.127.255.255 | 100.64.0.0/10 | 运营商 CGNAT(拿到这种地址说明你不是真公网 IP) |
注意
172.16.0.0/12不是172.0.0.0:172.32.x.x是公网地址,常有人搞错。
九、历史小知识:A、B、C 类地址
早期没有子网掩码的灵活写法,按第一段数字固定分类:
| 类别 | 第一段 | 默认掩码 |
|---|---|---|
| A 类 | 1 ~ 126 | /8 |
| B 类 | 128 ~ 191 | /16 |
| C 类 | 192 ~ 223 | /24 |
问题是太死板:一个公司要 300 台主机,C 类不够、B 类又浪费 6 万多个地址。1993 年起推广CIDR(无类别域间路由),前缀长度可以任意设。现在的网络已经不按类别划分,只是很多教材和老设备还保留这些说法。
十、用代码算子网(C#)
联机游戏里常见需求:判断一个玩家是不是在同一局域网(比如局域网对战优先直连)。
usingSystem.Net;publicstaticclassSubnet{// IPv4 地址转成 32 位整数staticuintToUInt(IPAddressip){byte[]b=ip.GetAddressBytes();return(uint)(b[0]<<24|b[1]<<16|b[2]<<8|b[3]);}staticIPAddressToIP(uintv)=>newIPAddress(new[]{(byte)(v>>24),(byte)(v>>16),(byte)(v>>8),(byte)v});// /24 → 0xFFFFFF00publicstaticuintMaskFromPrefix(intprefix){// ⚠️ C# 里 uint 左移 32 位等于不移位,所以 /0 要单独处理returnprefix==0?0u:uint.MaxValue<<(32-prefix);}publicstaticboolIsSameSubnet(stringa,stringb,intprefix){uintmask=MaskFromPrefix(prefix);return(ToUInt(IPAddress.Parse(a))&mask)==(ToUInt(IPAddress.Parse(b))&mask);}publicstatic(IPAddress network,IPAddress broadcast)Range(stringip,intprefix){uintmask=MaskFromPrefix(prefix);uintaddr=ToUInt(IPAddress.Parse(ip));uintnetwork=addr&mask;// 主机位清零uintbroadcast=network|~mask;// 主机位全置 1return(ToIP(network),ToIP(broadcast));}}使用:
Subnet.IsSameSubnet("192.168.1.10","192.168.1.20",24);// trueSubnet.IsSameSubnet("192.168.1.10","192.168.2.20",24);// falsevar(net,bc)=Subnet.Range("192.168.1.130",26);// net = 192.168.1.128,bc = 192.168.1.191网络地址 =
IP & 掩码,广播地址 =网络地址 | ~掩码。两行位运算,就是整篇文章的核心。
十一、和游戏开发的关系
| 场景 | 和子网掩码的关系 |
|---|---|
| 局域网发现房间 | 主机向广播地址(如 192.168.1.255)发 UDP 包"我开了房间",同一子网的玩家都能收到;跨子网收不到 |
| 局域网联机找不到对方 | 两台电脑可能在不同子网(比如一台连有线、一台连访客 Wi-Fi) |
| 服务器白名单 | 只允许10.0.5.0/24(公司内网)访问 GM 后台 |
| 云服务器网络规划 | VPC 用 /16,按用途切成多个 /24:网关层、逻辑服、数据库 |
| 防作弊 / 限流 | 按 /24 统计同一网段的请求数,识别批量注册的小号 |
Unity 局域网发现的提醒:用255.255.255.255(受限广播)通常只发到本地链路;用子网广播地址(如 192.168.1.255)需要先根据本机 IP 和掩码算出来 —— 用的就是上面的Range方法。
十二、掩码填错会怎样?
本机192.168.1.10,网关192.168.1.1:
| 填的掩码 | 电脑以为的网段 | 后果 |
|---|---|---|
| 255.255.255.0(正确) | 192.168.1.0 ~ .255 | 一切正常 |
| 255.255.0.0(太大) | 192.168.0.0 ~ 192.168.255.255 | 访问 192.168.2.5 时,电脑以为是"邻居",直接 ARP 找它,没人回应,连不上(它其实在另一个子网,要经过网关) |
| 255.255.255.240(太小) | 192.168.1.0 ~ .15 | 访问 192.168.1.50 时,以为不在本网段,绕去网关;能否通取决于路由器,可能多绕一圈,也可能不通 |
| 255.255.255.100(非法) | — | 系统报错或拒绝保存 |
掩码太大:以为是邻居,结果敲门没人应。掩码太小:明明是邻居,却跑去快递站寄。
十三、常见的坑
| 坑 | 现象 | 解决 |
|---|---|---|
| 把网络地址或广播地址分给设备 | 设备无法正常通信 | 主机位全 0 / 全 1 的地址不要用(/31、/32 除外) |
| 可用主机数忘了减 2 | 规划时地址不够 | 公式是 2ⁿ − 2 |
| 网关不在掩码算出的网段内 | 完全上不了外网 | 网关必须和本机同网段 |
| 同一网段不同设备掩码不一致 | 有的能互通,有的单向不通 | 统一由 DHCP 下发 |
| 172.32.x.x 当成私有地址 | 和公网地址冲突 | 私有范围只到 172.31.255.255 |
| 内网网段和 VPN / 云 VPC 重叠 | 连上 VPN 后某些地址访问不了 | 规划时避开常见的 192.168.0.0/24、192.168.1.0/24 |
代码里uint << 32 | /0 掩码算成全 1 | 单独处理 prefix = 0 |
| 以为跨子网也能收到广播 | 局域网联机找不到房间 | 广播不跨路由器,需要手动输入 IP 或用服务器中转 |
十四、顺带一提:IPv6
IPv6 地址是 128 位,不再写"子网掩码"的十进制形式,只用前缀长度:
2001:db8:abcd:12::10/64- 局域网几乎统一用/64:前 64 位是网络,后 64 位是主机
- 没有广播地址,改用组播
- 地址多到不用精打细算,划分规则比 IPv4 简单得多
一句话总结
子网掩码 = 一串连续的 1 加一串连续的 0:1 标记网络号,0 标记主机号。
核心运算只有两行:网络地址 = IP & 掩码,广播地址 = 网络地址 | ~掩码。两个 IP 算出的网络地址相同,就直接通信;不同,就交给网关。
可用主机数 =2^(主机位) − 2;速算时记住块大小 = 256 − 掩码中那一段的值。