如何用Python 2.6高效匹配IP列表与CIDR网络并记录归属网络
高效判断IP地址所属CIDR网络(Python 2.6实现)
需求描述
拥有一个IPv4地址字符串列表,以及一个CIDR格式网络字符串列表,需要用Python 2.6实现高效方法,判断每个IP地址属于哪些网络,并记录每个IP对应的所属网络列表。
示例输入
ip_addresses = ["127.0.0.1", "192.168.0.1", "127.0.1.1"] networks = ["127.0.0.0/24", "127.0.0.0/16"]
预期结果
results = {"127.0.0.1": ["127.0.0.0/24", "127.0.0.0/16"], "192.168.0.1": [], "127.0.1.1": ["127.0.0.0/16"]}
原方案问题
原本计划使用ipaddress模块实现,但Python 2.6并未内置该模块;且当网络列表超过10万条时,直接遍历匹配的效率有优化空间(尽管IP列表通常少于10个)。
高效实现方案
核心思路
- 预处理网络:将所有CIDR网络转换为起始IP整数、结束IP整数和原CIDR字符串的元组,避免重复解析开销。
- IP转整数:将IP地址转换为32位无符号整数,用区间匹配替代复杂的IP逻辑判断。
- 快速匹配:对每个IP整数,遍历预处理后的网络元组,判断是否落在网络的IP区间内,收集所有匹配的CIDR字符串。
代码实现
def ip_to_int(ip_str): """将IPv4字符串转换为32位无符号整数""" octets = map(int, ip_str.split('.')) return (octets[0] << 24) | (octets[1] << 16) | (octets[2] << 8) | octets[3] def cidr_to_range(cidr_str): """将CIDR字符串转换为起始IP整数、结束IP整数和原CIDR字符串""" ip_part, prefix_part = cidr_str.split('/') prefix_len = int(prefix_part) ip_int = ip_to_int(ip_part) # 计算子网掩码(32位无符号) mask = 0xFFFFFFFF << (32 - prefix_len) # 网络起始IP start_ip = ip_int & mask # 网络结束IP end_ip = start_ip | (~mask & 0xFFFFFFFF) return (start_ip, end_ip, cidr_str) def match_ips_to_networks(ip_list, cidr_list): # 预处理所有CIDR网络,仅执行一次 network_ranges = [cidr_to_range(cidr) for cidr in cidr_list] results = {} for ip_str in ip_list: ip_int = ip_to_int(ip_str) matched = [] for start, end, cidr in network_ranges: if start <= ip_int <= end: matched.append(cidr) results[ip_str] = matched return results # 测试示例 if __name__ == "__main__": ip_addresses = ["127.0.0.1", "192.168.0.1", "127.0.1.1"] networks = ["127.0.0.0/24", "127.0.0.0/16"] results = match_ips_to_networks(ip_addresses, networks) print(results)
效率说明
- 预处理阶段:10万条CIDR的解析在Python中仅需数秒,属于一次性开销。
- 匹配阶段:每个IP遍历10万条网络的判断是简单的整数比较,单IP匹配耗时约0.1-0.2秒,10个IP总耗时在2秒以内,完全满足需求。
- 若需进一步优化,可将网络按前缀长度分组或构建前缀树,但对于IP数量极少的场景,上述方案性价比最高,无需额外复杂实现。
内容的提问来源于stack exchange,提问作者Calab
相关产品推荐
相关产品推荐

