Python处理IP地址的利器IPy

news/2024/2/29 2:54:43

文章目录

  • 一、安装IPy
  • 二、IP类:处理单网段
    • 2.1 查看网段包含的IP地址
    • 2.2 查看地址是IPv4还是IPv6
    • 2.3 格式化输出地址
    • 2.4 已知掩码求网段
    • 2.5 将IP地址转换为字符串
    • 2.6 处理IP地址段的包含关系
  • 三、IPSet类:处理多网段
    • 3.1 多网段聚合处理
    • 3.2 判断多个网段是否相交
    • 3.3 输出网段的IP地址数量
    • 附:IPSet类源码

IP地址的规划,不仅是网络设计中的重中之重,还会直接影响网络的转发效率和扩展性。

很多从事网络工作多年的朋友,免不了要在工作中重复计算诸如网段、子网掩码、广播地址、子网数。还要判断IP网段的包含关系和对多个IP地址段进行汇总等等。

如果计算数据量特别大,不仅费时费力,还容易出错。

Python有一个非常强大的第三方库IPy,适用于Python 2.6-3.7版本,可以帮助我们完成此类计算任务。大家可以参见IPy的项目地址:https://github.com/autocracy/python-ipy

一、安装IPy

1、打开终端;
2、输入:pip list查看自己安装的库,如果有,就不需要安装了。
3、如果没有IPy,则输入pip install IPy即可

pip install IPy

二、IP类:处理单网段

IP类允许对IPv4和IPv6地址和网络中使用的大多数符号进行轻松的解析和处理。

2.1 查看网段包含的IP地址

from IPy import IP
ip = IP('127.0.0.0/30')
for x in ip:print(x)

输出如下:

127.0.0.0
127.0.0.1
127.0.0.2
127.0.0.3

2.2 查看地址是IPv4还是IPv6

print(IP('10.0.0.0/8').version())  # 4
print(IP('::1').version())  # 6

2.3 格式化输出地址

  • IPv4
print(IP(0x7f000001))  # 127.0.0.1
print(IP('0x7f000001'))  # 127.0.0.1
print(IP('127.0.0.1'))  # 127.0.0.1
print(IP('10'))  # 10.0.0.0
  • IPv6
print(IP('1080:0:0:0:8:800:200C:417A'))  # 1080::8:800:200c:417a
print(IP('1080::8:800:200C:417A'))  # 1080::8:800:200c:417a
print(IP('::1'))  # ::1 
print(IP('::13.1.68.3'))  # ::d01:4403
  • 子网掩码及网段前缀转换
print(IP('127.0.0.0/8'))  # 127.0.0.0/8
print(IP('127.0.0.0/255.0.0.0'))  # 127.0.0.0/8
print(IP('127.0.0.0-127.255.255.255'))  # 127.0.0.0/8

2.4 已知掩码求网段

已知IP地址的子网掩码,求出该地址所在的网段:

print(IP('127.0.0.1/255.0.0.0', make_net=True))  # 127.0.0.0/8
print(IP('127.0.0.1').make_net('255.0.0.0'))  # 127.0.0.0/8

2.5 将IP地址转换为字符串

可以通过strNomal方法指定不同的wantprefixlen参数定制不同输出类型的网段输出为字符串。

wantprefixlen == 0 / None     无返回   1.2.3.0
wantprefixlen == 1            返回前缀prefix                 1.2.3.0/24
wantprefixlen == 2            返回网段netmask                1.2.3.0/255.255.255.0
wantprefixlen == 3            返回IP地址范围lastip                 1.2.3.0-1.2.3.255

示例如下:

IP('10.0.0.0/32').strNormal()  # '10.0.0.0'
IP('10.0.0.0/24').strNormal()  # '10.0.0.0/24'
IP('10.0.0.0/24').strNormal(0)  # '10.0.0.0'
IP('10.0.0.0/24').strNormal(1)  # '10.0.0.0/24'
IP('10.0.0.0/24').strNormal(2)  # '10.0.0.0/255.255.255.0'
IP('10.0.0.0/24').strNormal(3)  # '10.0.0.0-10.0.0.255'

2.6 处理IP地址段的包含关系

涉及处理两个网段是否包含的关系,IPy中的IP方法也提供了这个功能,他会返回一个布尔值告诉我们是否包含:

  • 判断两个IP网段的大小:
from IPy import IP
IP('1.1.1.0/24') < IP('2.2.2.0/24')
# True
  • 判断一个IP地址是否包含于另一个IP网段
from IPy import IP
'192.168.100.1' in IP('192.168.100.0/27')
# True
  • 判断一个IP网段是否被另一个IP网段包含
from IPy import IP
IP('192.168.2.0/24') in IP('192.168.0.0/23')
# Falsefrom IPy import IP
IP('192.168.1.0/24') in IP('192.168.0.0/23')
# True

三、IPSet类:处理多网段

将相邻的网段的进行聚合操作,将得到两者的父网段。IPSet类可提供更复杂的范围映射和聚合要求,其保存任何数量的唯一地址范围,并对重叠范围进行聚合处理。

3.1 多网段聚合处理

>>> from IPy import IP, IPSet
IP('10.0.0.0/22') - IP('10.0.2.0/24')
# IPSet([IP('10.0.0.0/23'), IP('10.0.3.0/24')])IPSet([IP('10.0.0.0/23'), IP('10.0.3.0/24'), IP('10.0.2.0/24')])
# IPSet([IP('10.0.0.0/22')])s = IPSet([IP('10.0.0.0/22')])
s.add(IP('192.168.1.0/29'))   # 增加网段
s
# IPSet([IP('10.0.0.0/22'), IP('192.168.1.0/29')])s.discard(IP('192.168.1.2'))   # 删除网段
s
# IPSet([IP('10.0.0.0/22'), IP('192.168.1.0/31'), IP('192.168.1.3'), IP('192.168.1.4/30')])

3.2 判断多个网段是否相交

IPSet支持isdisjoint方法,用来判断网段之间是否是 “不相交” 的:

s.isdisjoint(IPSet([IP('192.168.0.0/16')]))
# False
s.isdisjoint(IPSet([IP('172.16.0.0/12')]))
# True

IPSet支持&方法,用来判断网段之间是否是 “相交” 的:

s & IPSet([IP('10.0.0.0/8')])
# IPSet([IP('10.0.0.0/22')])

3.3 输出网段的IP地址数量

IPSet([IP('10.0.0.0/24')]).len()  # 256IPSet([IP('10.0.0.0/22')]).len()  # 1024

【注意】:当使用IPv6地址时,最好使用 IP().len() 方法而不是len(IP)方法。整数值大于64位的地址可能使得第二种方法出Bug,具体可以参考 http://stackoverflow.com/questions/15650878 了解更多信息。

附:IPSet类源码

class IPSet(MutableSet):def __init__(self, iterable=[]):# Make sure it's iterable, otherwise wrapif not isinstance(iterable, Iterable):raise TypeError("'%s' object is not iterable" % type(iterable).__name__)# Make sure we only accept IP objectsfor prefix in iterable:if not isinstance(prefix, IP):raise ValueError('Only IP objects can be added to an IPSet')# Store and optimizeself.prefixes = iterable[:]self.optimize()def __contains__(self, ip):valid_masks = self.prefixtable.keys()if isinstance(ip, IP):#Don't dig through more-specific rangesip_mask = ip._prefixlenvalid_masks = [x for x in valid_masks if x <= ip_mask]for mask in sorted(valid_masks):i = bisect.bisect(self.prefixtable[mask], ip)# Because of sorting order, a match can only occur in the prefix# that comes before the result of the search.if i and ip in self.prefixtable[mask][i - 1]:return Truedef __iter__(self):for prefix in self.prefixes:yield prefixdef __len__(self):return self.len()def __add__(self, other):return IPSet(self.prefixes + other.prefixes)def __sub__(self, other):new = IPSet(self.prefixes)for prefix in other:new.discard(prefix)return newdef __and__(self, other):left = iter(self.prefixes)right = iter(other.prefixes)result = []try:l = next(left)r = next(right)while True:# iterate over prefixes in order, keeping the smaller of the# two if they overlapif l in r:result.append(l)l = next(left)continueelif r in l:result.append(r)r = next(right)continueif l < r:l = next(left)else:r = next(right)except StopIteration:return IPSet(result)def __repr__(self):return '%s([' % self.__class__.__name__ + ', '.join(map(repr, self.prefixes)) + '])'def len(self):return sum(prefix.len() for prefix in self.prefixes)def add(self, value):# Make sure it's iterable, otherwise wrapif not isinstance(value, Iterable):value = [value]# Check typefor prefix in value:if not isinstance(prefix, IP):raise ValueError('Only IP objects can be added to an IPSet')# Append and optimizeself.prefixes.extend(value)self.optimize()def discard(self, value):# Make sure it's iterable, otherwise wrapif not isinstance(value, Iterable):value = [value]# This is much faster than iterating over the addressesif isinstance(value, IPSet):value = value.prefixes# Removefor del_prefix in value:if not isinstance(del_prefix, IP):raise ValueError('Only IP objects can be removed from an IPSet')# First check if this prefix contains anything in our listfound = Falsed = 0for i in range(len(self.prefixes)):if self.prefixes[i - d] in del_prefix:self.prefixes.pop(i - d)d = d + 1found = Trueif found:# If the prefix was bigger than an existing prefix, then it's# certainly not a subset of one, so skip the restcontinue# Maybe one of our prefixes contains this prefixfound = Falsefor i in range(len(self.prefixes)):if del_prefix in self.prefixes[i]:self.prefixes[i:i+1] = self.prefixes[i] - del_prefixbreakself.optimize()def isdisjoint(self, other):left = iter(self.prefixes)right = iter(other.prefixes)try:l = next(left)r = next(right)while True:if l in r or r in l:return Falseif l < r:l = next(left)else:r = next(right)except StopIteration:return Truedef optimize(self):# The algorithm below *depends* on the sort orderself.prefixes.sort()# First eliminate all values that are a subset of other valuesaddrlen = len(self.prefixes)i = 0while i < addrlen:# Everything that might be inside this prefix follows# directly behind itj = i+1while j < addrlen and self.prefixes[j] in self.prefixes[i]:# Mark for deletion by overwriting with Noneself.prefixes[j] = Nonej += 1# Continue where we left offi = j# Try to merge as many prefixes as possiblerun_again = Truewhile run_again:# Filter None values. This happens when a subset is eliminated# above, or when two prefixes are merged belowself.prefixes = [a for a in self.prefixes if a is not None]# We'll set run_again to True when we make changes that require# re-evaluation of the whole listrun_again = False# We can merge two prefixes that have the same version, same# prefix length and differ only on the last bit of the prefixaddrlen = len(self.prefixes)i = 0while i < addrlen-1:j = i + 1try:# The next line will throw an exception when merging# is not possibleself.prefixes[i] += self.prefixes[j]self.prefixes[j] = Nonei = j + 1run_again = Trueexcept ValueError:# Can't be merged, see if position j can be mergedi = j# O(n) insertion now by prefix means faster searching on __contains__# when lots of ranges with the same length existself.prefixtable = {}for address in self.prefixes:try:self.prefixtable[address._prefixlen].append(address)except KeyError:self.prefixtable[address._prefixlen] = [address]

https://www.xjx100.cn/news/3118757.html

相关文章

Spring Cloud Gateway集成SpringDoc,集中管理微服务API

本文目标 Spring Cloud微服务集成SpringDoc&#xff0c;在Spring Cloud Gateway中统一管理微服务的API&#xff0c;微服务上下线时自动刷新SwaggerUi中的group组。 依赖版本 框架版本Spring Boot3.1.5Spring Cloud2022.0.4Spring Cloud Alibaba2022.0.0.0Spring Doc2.2.0Nac…

数字化转型的核心是数据,还是应用?_光点科技

数字化转型是当今世界各行各业的热门话题。它不仅仅是将传统的业务流程、产品和服务数字化&#xff0c;更是一种全面的业务战略转变。在这个转变过程中&#xff0c;数据和应用都扮演着至关重要的角色。但究竟哪一个是数字化转型的核心&#xff1f;这个问题值得深入探讨。 我们来…

base64转PDF

今天做皖事通的对接&#xff0c;下载电子证照后发现回传的是base64&#xff0c;调试确认是个麻烦事&#xff0c;网上搜了一下没有base64转PDF的在线预览功能&#xff0c;只能自己写个调试工具了&#xff0c;以下是通过纯JS方式写的代码&#xff0c;可直接拿去使用&#xff1a; …

科研学习|论文解读——Deep learning for anomaly detection in log data: a survey

摘要 自动日志文件分析能够及早发现系统故障等相关事件。特别是&#xff0c;自学习异常检测技术能够捕捉日志数据中的模式&#xff0c;然后向系统操作员报告意外的日志发生&#xff0c;而无需提前提供或手动建模异常场景。最近&#xff0c;越来越多的利用深度学习方法来实现此目…

TS版LangChain实战:基于文档的增强检索(RAG) | 京东云技术团队

LangChain LangChain是一个以 LLM &#xff08;大语言模型&#xff09;模型为核心的开发框架&#xff0c;LangChain的主要特性&#xff1a; 可以连接多种数据源&#xff0c;比如网页链接、本地PDF文件、向量数据库等允许语言模型与其环境交互封装了Model I/O&#xff08;输入…

基于Spring、SpringMVC、MyBatis的在线云音乐网站

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于Spring、SpringMVC、MyBatis的在线云…

Pycharm2020.3.5激活方式

激活插件链接&#xff1a;https://pan.baidu.com/s/1tPd7V4pKUx0Z6fSKumLjTQ 提取码&#xff1a;lr12 1.pycharm主界面点开设置如下&#xff1a; 2.点击 Plugins 然后依次点击&#xff1a;小齿轮->选择本地安装&#xff08;下图&#xff09; 3.找到存放插件的目录&#xf…

如何跑通跨窗口渲染:multipleWindow3dScene

New 这是一个跨窗口渲染的示例&#xff0c;用 Three.js 和 localStorage 在同一源&#xff08;同产品窗口&#xff09;上跨窗口设置 3D 场景。而这也是本周推特和前端圈的一个热点&#xff0c;有不少人在争相模仿它的实现&#xff0c;如果你对跨窗口的渲染有兴趣&#xff0c;可…