Python-计算IP范围以下IP的最佳方法

时间:2018-12-19 23:48:33

标签: python python-2.7 ip

我有一个python脚本,可从arp表中获取所有IP,并将其分配给变量。我有一个for循环,它创建另外两个变量start_IP,它们包含一个子网的第一个IP,而last_IP包含相同子网中的最后一个IP。对于每个循环,我将有不同的开始和结束IP。

我正在尝试检查包含所有IP的变量,并查看每个子网下有多少IP。

什么是最好的方法?这是一个硬编码的示例: 计数= 0

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <string name="hello">Hello World, Click Me!</string>
   <string name="app_name">SpinnerArray</string>
   <string name="on_off">On or Off</string>
   <string-array name="spinnerArray">
      <item>On</item>
      <item>Off</item>
   </string-array>
</resources>

是否有更好的更快的方法?

2 个答案:

答案 0 :(得分:3)

两种方式。简单的方法:

IP地址逐字节比较八位字节。有趣的是,Python列表按元素进行比较。因此,如果仅将IP地址按点分隔并将列表映射到int,则可以正确比较它们。

更简单的方法:

ipaddress.ip_address是可比较的,只要比较的地址是同一版本(IPv4或IPv6)即可。

但是,字符串比较不能提供正确的IP地址排序:

'1.12.1.1' < '1.2.1.1'
# => True (should be False)

除这些问题外,您的代码都可以。它可以写得更简洁:

import ipaddress
arps = ['10.20.30.130','10.20.30.131','10.20.30.132', '10.20.30.133', 
    '10.20.30.136', '10.20.30.137', '10.20.30.138', '10.20.30.139', 
    '10.20.30.140', '10.20.30.141', '10.20.30.143', '10.20.30.149']
start_ip = "10.20.30.132"
end_ip = "10.20.30.142"

start_ip_ip = ipaddress.ip_address(start_ip)
end_ip_ip = ipaddress.ip_address(end_ip)

sum(1 for ip in arps if start_ip_ip <= ipaddress.ip_address(ip) <= end_ip_ip)
# => 8

如果您特别想查看特定子网中的地址,那么即使您知道子网规格,甚至不需要使用起始地址和结束地址:

ipaddress.ip_address('192.168.1.17') in ipaddress.ip_network('192.168.0.0/16')
# => True

答案 1 :(得分:2)

我可以想到以下两种解决方案。方法1的时间复杂度为O(N),方法2的时间复杂度为O(Nlog N)。正如Amadan所建议的那样,IP地址需要预先进行预处理。

import bisect

arps = ['10.20.30.130','10.20.30.131','10.20.30.132', '10.20.30.133', 
'10.20.30.136', '10.20.30.137', '10.20.30.138', '10.20.30.139', '10.20.30.140', '10.20.30.141', '10.20.30.143', '10.20.30.149']
start_ip = "10.20.30.132"
end_ip = "10.20.30.142"

# Padding zeros to the IP addresses to make sure they are directly comparable
def padding(s):
    return s.zfill(3)

arps = [".".join(list(map(padding, x.split(".")))) for x in arps]
start_ip = ".".join(list(map(padding, start_ip.split("."))))
end_ip   = ".".join(list(map(padding, end_ip.split("."))))

# Method 1: Pythonic one-liner
print(sum(start_ip <= x <= end_ip for x in arps))

# Method 2: Sort and binary search
def find_lt(a, x):
    i = bisect.bisect_right(a, x)
    if i:
        return i - 1
    else:
        return 0

def find_gt(a, x):
    i = bisect.bisect_right(a, x)
    if i != len(a):
        return i
    else:
        return i

arps.sort()
print(find_gt(arps, end_ip) - find_lt(arps, start_ip))