AIGC标识 用 Python 看一眼 IP 地址的本质:CIDR、子网、私有段都在哪

之前有个同事问我"192.168.1.0/24 到底是几个 IP",我愣了一下——这东西上学时背过,真要写出来反而卡壳。后来我发现,与其死记硬背,不如用 Python 的 ipaddress 模块把这几个概念直接跑一遍。几个最常被搞混的点:CIDR 后面的数字什么意思、私有段到底有哪些、怎么判断两个 IP 是不是一个网段。

CIDR 后面的 /24 到底啥意思

/24 不是"24 个 IP",而是子网掩码里前 24 位是网络号。换句话说,一个 C 段(比如 192.168.1.0/24)固定是 256 个地址,/16 是 65536 个。

import ipaddress

net = ipaddress.ip_network('192.168.1.0/24')
print(net.num_addresses)          # 256
print(net.network_address)        # 192.168.1.0
print(net.broadcast_address)      # 192.168.1.255

network_address 是网段起点,broadcast_address 是广播地址。真实能分配给设备的,其实是中间的 254 个(去掉网络号和广播地址)。

私有段有哪些,怎么判断

IPv4 里常见的私有段就那么几块:

  • 10.0.0.0/8:一个 A 类大私网
  • 172.16.0.0/12:16 个 B 类
  • 192.168.0.0/16:256 个 C 类,家用路由器基本都在这
  • 127.0.0.0/8:回环,本机
  • 169.254.0.0/16:链路本地,DHCP 拿不到地址时会自动配

ipaddress 一把就能分类,不用自己背:

def classify(ip_str):
    ip = ipaddress.ip_address(ip_str)
    if ip.is_loopback:   return '回环'
    if ip.is_private:    return '私有'
    if ip.is_global:     return '公网'
    if ip.is_link_local: return '链路本地'
    return '其他'

for ip in ['192.168.1.1', '8.8.8.8', '127.0.0.1', '10.0.0.5', '169.254.0.1']:
    print(ip, '->', classify(ip))

跑出来是 192.168.1.1 -> 私有8.8.8.8 -> 公网127.0.0.1 -> 回环10.0.0.5 -> 私有169.254.0.1 -> 私有。注意 169.254ipaddress 里算私有(它确实是保留段),但严格说是链路本地,平时几乎用不到。

子网怎么划

有时候一个 /8 太大,要切成小段分给不同部门。用 subnets() 就行:

subs = list(ipaddress.ip_network('10.0.0.0/8').subnets(new_prefix=16))
print(len(subs))   # 256,也就是 256 个 /16

new_prefix 越大,段越小、数量越多。这是数学关系,不是配置,所以别指望"切一刀能省 IP"。

两个 IP 是不是一个网段

这是排障里最常见的问题:为什么 A 能连 B 但连不上 C?先看看是不是一个子网。

def same_subnet(a, b, prefix):
    na = ipaddress.ip_network(f'{a}/{prefix}', strict=False)
    nb = ipaddress.ip_network(f'{b}/{prefix}', strict=False)
    return na.network_address == nb.network_address

print(same_subnet('192.168.1.10', '192.168.1.200', 24))  # True
print(same_subnet('192.168.1.10', '192.168.2.10', 24))   # False

strict=False 很关键:它会容忍你给的 IP 不是网段起点(比如 192.168.1.10/24),自动归到 192.168.1.0/24,不然直接报错。

一点体会

这些东西教科书上讲得很绕,但落到 ipaddress 里其实就是几个属性和方法。is_privateis_globalnum_addressessubnets() 这几个记住,平时排障、写网络相关脚本基本够用了。

我自己的习惯是:每次配新网段,先用 ip_network 跑一遍确认地址范围,避免把广播地址也配进去了——这种低级错误我犯过不止一次。

posted @ 2026-08-13 10:36  IP观察室  阅读(0)  评论(0)    收藏  举报