Python 中的 ipaddress 模块如何处理 IP

How ipaddress module in Python handles IPs

我被要求做一个应用程序来提供子网可能的主机总数,遗憾的是我不能使用 Python 提供的 ipaddress 模块所以我需要编写自己的方法来检查和验证输入的数据
我的代码是这样的:

def IP_Validation(chk_IP_vaild):
    if chk_IP_vaild.count(".") == 3 and all(isIP(i) for i in chk_IP_vaild.split(".")):
        return True
    return False
        
def isIP(IP_String):
    try:
        return str(int(IP_String)) == IP_String and 0 <= int(IP_String) <= 255
    except:
        return False

def Calc_Networks(IP_One , IP_Two):
    if IP_Validation(IP_One) and IP_Validation(IP_Two):
        print (IP_One,IP_Two)
    else:
        print ("There is an error")


Calc_Networks("172.11.254.1", "172.1.254.")
Calc_Networks("172.11.254.1", "172.1.254.0")

输出

There is an error
172.11.254.1 172.1.254.0

但这只检查输入的 IP 是否为 IPv4,所以我在网上搜索和检查解决方案,我遇到了这个:

import ipaddress
def calc_inclusive_subnet(ip1, ip2): #accepts 2 IP strings
    #make IP Address objects
    ip1_obj=ipaddress.IPv4Address(ip1)
    ip2_obj=ipaddress.IPv4Address(ip2)

    if ip1_obj<=ip2_obj:
        min_ip=ip1_obj
        max_ip=ip2_obj
    else:
        min_ip=ip2_obj
        max_ip=ip1_obj   
    distance = int(max_ip)-int(min_ip) #**
    return distance

print (calc_inclusive_subnet("192.168.1.0", "192.168.2.255"))

输出

511

我注意到,如果我对使用 ipaddress 模块声明的两个 IP 进行减法运算,它会毫无问题地正确执行,因此我转到 Docs 以了解该模块如何处理IP,所以我可以使用类似的方法


使用 代码 1 进行减法会出现以下错误:

def Calc_Networks(IP_One , IP_Two):
    if IP_Validation(IP_One) and IP_Validation(IP_Two):
        dis = int(IP_Two) - int(IP_One)
        return dis

输出为:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-154-9e53188ce6f1> in <module>
     16 
     17 
---> 18 print(Calc_Networks("172.11.254.1", "172.1.254.1"))
     19 Calc_Networks("172.11.254.1", "172.1.254.")

<ipython-input-154-9e53188ce6f1> in Calc_Networks(IP_One, IP_Two)
     12 def Calc_Networks(IP_One , IP_Two):
     13     if IP_Validation(IP_One) and IP_Validation(IP_Two):
---> 14         dis = int(IP_Two) - int(IP_One)
     15         return dis
     16 

ValueError: invalid literal for int() with base 10: '172.1.254.1'

这些帖子 1 & 2 也帮不了我!

提前致谢

您的 Calc_Networks 代码不起作用但 calc_inclusive_subnet 起作用的原因是在 calc_inclusive_subnet 中将 ipaddress.IPv4Address 传递给了 int,它有一个 __int__ 方法,并为您提供所需的东西。但是,您的代码只是将字符串表示形式传递给 int,它会尝试将 IP 地址解析为普通 int,而 "172.11.254.1" 不是。

如果你不想使用ipaddress你仍然可以实现一个函数来将IP地址解析成一个整数:

def parse_ip_to_int(ip_address):
    octets = ip_address.split('.')
    return int.from_bytes(map(int, octets), 'big')

上面的函数将ip_address拆分成一个字符串列表,每个字符串对应一个地址的八位字节(因此对于"172.11.254.1"["172", "11", "254", "1"])。然后我们使用 map 将这些字符串转换为 ints。最后,我们使用有用的 int.from_bytes,它允许我们将可迭代的八位字节转换为一个大整数。这也可以通过循环和向左移位 8 位来实现。int.from_bytes'big' 的第二个参数表示最重要的八位字节是第一个,这就是 IPv4 地址的编码方式。

从这里我们现在可以正确实现您的 Calc_Networks 功能。我通过使用 abs 来简化它,以确保我们获得的距离是正的,而不是像原来的 calc_inclusive_subnet.

那样找到最小值和最大值
def Calc_Networks(IP_One, IP_Two):
    if IP_Validation(IP_One) and IP_Validation(IP_Two):
        return abs(parse_ip_to_int(IP_One) - parse_ip_to_int(IP_Two))

与您的初始实现类似,如果验证失败,则返回 None。最后一点,虽然我所展示的确实产生了与你所展示的 calc_inclusive_subnet 相同的结果,但该函数所做的只是计算从起始地址到(但不包括)结束地址的地址数地址。您想要的行为可能会有所不同。