前言
最近在工作中需要对用户输入的ip进行重复性校验,之前处理的都是单ip,直接通过ip字符串比较即可。现在用户输入的是ip+掩码的方式,也就是支持ip范围输入,这样之前的校验方式就行不通了。
说明
那么如何解决呢?我们都知道ip4是通过"点分十进制"来表示的,本质上就是一个二进制的整数,只需要将十进制的表示的IP转换为二进制整数,通过数值进行比较即可。
对于单ip而言,直接转换为整数,对于ip+掩码的形式(也就是ip范围)获取范围的开始值和结束值就可以确定其范围了。
这里介绍如下:
- 1.单ip转换为整数
- 2.ip+掩码形式的IP段,获取开始和结束ip
单个ip转换为整数
# ip4转换为int类型
ip4_to_int = lambda ip: sum([256 ** j * int(i) for j, i in enumerate(ip.split('.')[::-1])])
ip+掩码形式的ip获取起始范围
1.原理(以192.168.1.53/27为例)
192.168.1.53的二进制表示 | 11000000.10101000.00000001.00110101 | |
---|---|---|
子网掩码 | 11111111.11111111.11111111.11100000 | 27表示有27个1 |
网络地址 | 11000000.10101000.00000001.00100000 | 子网掩码与ip地址进行与运算,得到网络地址(与运算就是全1为1,其它都为0) |
广播地址 | 11000000.10101000.00000001.00111111 | 在网络地址的基础上,将主机地址全部填充为1 |
其中网路地址就是ip段的开始值,广播地址就是ip段的结束值.
2.具体代码实现
def get_ip_mask_range(ip, mask):
"""获取掩码ip的整数范围(包括网络地址和广播地址)"""
# ip4转换为int类型
ip4_to_int = lambda ip: sum([256 ** j * int(i) for j, i in enumerate(ip.split('.')[::-1])])
if mask:
# 子网掩码
sub_mask = '0b{0:0<32}'.format(int("".join(['1' for i in range(mask)])))
# 网络地址
network = ip4_to_int(ip) & int(sub_mask, 2) # 与运算,获取网络地址
# 主机地址
host = '0b{0:0>32}'.format(int("".join(['1' for i in range(32 - mask)])))
print(host)
# 广播地址
broad = network | int(host, 2) # 或运算,将主机号置为1
print("network:{}, broad:{}".format(network, broad))
start_ip_int, end_ip_int = network, broad
else:
start_ip_int = end_ip_int = ip4_to_int(ip)
return start_ip_int, end_ip_int
喜欢点个赞!!!