You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中不使用ipaddress模块检测IP地址是否为保留地址

IPv4保留地址检测的性能优化实践

需求:不使用ipaddress模块,判断给定IPv4地址是否属于保留地址范围。

保留地址原始列表

根据IPv4保留地址定义,列表如下:

RESERVED_IPV4 = [
    '0.0.0.0/8',
    '10.0.0.0/8',
    '100.64.0.0/10',
    '127.0.0.0/8',
    '169.254.0.0/16',
    '172.16.0.0/12',
    '192.0.0.0/24',
    '192.0.2.0/24',
    '192.88.99.0/24',
    '192.168.0.0/16',
    '198.18.0.0/15',
    '198.51.100.0/24',
    '203.0.113.0/24',
    '224.0.0.0/4',
    '233.252.0.0/24',
    '240.0.0.0/4',
    '255.255.255.255/32'
]

转换为int类型起止范围

已将保留地址段转换为整数形式的起始、结束IP对:

RESERVED_IPV4 = [
    (0, 16777215),
    (167772160, 184549375),
    (1681915904, 1686110207),
    (2130706432, 2147483647),
    (2851995648, 2852061183),
    (2886729728, 2887778303),
    (3221225472, 3221225727),
    (3221225984, 3221226239),
    (3227017984, 3227018239),
    (3232235520, 3232301055),
    (3323068416, 3323199487),
    (3325256704, 3325256959),
    (3405803776, 3405804031),
    (3758096384, 4294967295)
]

方法1:朴素范围检查

将每个地址段转为range对象,检查IP是否在任一范围内:

RESERVED_IPV4_RANGES = [range(*e) for e in RESERVED_IPV4]

def is_reserved_range(ip):
    return any(ip in e for e in RESERVED_IPV4_RANGES)

性能测试:

import random
n = random.randrange(2**32)  # 生成随机IP整数

%timeit is_reserved_range(n)
# 1.92 µs ± 56 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

这种方法效率较低,因为ip in range的判断需要额外计算。


方法2:二进制前缀匹配

由于同一保留地址段内的IP共享相同二进制前缀,因此可以通过检查IP的二进制字符串是否以任一保留前缀开头来判断:

生成前缀

def longest_common_prefix(a, b):
    short = min(len(a), len(b))
    for i in range(short):
        if a[:i] != b[:i]:
            break
    return a[:i-1] if i else ''

RESERVED_IPV4_PREFIXES = tuple(longest_common_prefix(f'{a:032b}', f'{b:032b}') for a, b in RESERVED_IPV4)

生成的前缀列表:

('00000000',
 '00001010',
 '0110010001',
 '01111111',
 '1010100111111110',
 '101011000001',
 '110000000000000000000000',
 '110000000000000000000010',
 '110000000101100001100011',
 '1100000010101000',
 '110001100001001',
 '110001100011001101100100',
 '110010110000000001110001',
 '111')

检测函数

def is_reserved_prefix(ip):
    return f'{ip:032b}'.startswith(RESERVED_IPV4_PREFIXES)

性能测试:

%timeit is_reserved_prefix(n)
# 734 ns ± 6.59 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

该方法效率显著高于朴素范围检查。


方法3:直接整数范围比较

尝试直接比较IP整数是否在起止范围内:

%timeit any(a <= n <= b for a, b in RESERVED_IPV4)
# 1.71 µs ± 6.31 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

效率仍低于前缀匹配法。


方法4:位运算掩码匹配

尝试通过位运算实现前缀匹配,预先计算每个地址段的掩码:

RESERVED_IPV4_MASKS = []

for a, b in RESERVED_IPV4:
    count = b - a + 1
    x = count.bit_length() - 1
    y = 32 - x
    mask = ((1<<y)-1)<<x
    RESERVED_IPV4_MASKS.append((a, mask))

RESERVED_IPV4_MASKS = tuple(RESERVED_IPV4_MASKS)

实现1:使用any函数

def is_reserved_mask(ip):
    return any(ip & mask == start for start, mask in RESERVED_IPV4_MASKS)

性能测试:

%timeit is_reserved_mask(n)
# 2.12 µs ± 53.4 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

实现2:使用for循环提前返回

def is_reserved_mask(ip):
    for start, mask in RESERVED_IPV4_MASKS:
        if ip & mask == start:
            return True
    return False

性能测试:

%timeit is_reserved_mask(n)
# 1.3 µs ± 97.4 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

疑惑点

  1. 位运算理论上应该比字符串操作更高效,但实际测试中掩码匹配法的效率低于二进制前缀匹配法。
  2. 使用any函数的实现效率居然低于手动for循环提前返回的版本,不符合预期。

内容的提问来源于stack exchange,提问作者Ξένη Γήινος

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 16:29:58