Python - 计算 IP 范围内 IP 的最佳方法
Python - Best way to count IPs that fall under IP range
我有一个 python 脚本,它从 arp table 中获取所有 IP 并将其分配给一个变量。我有 for 循环创建另外两个变量 start_IP 包含子网的第一个 IP 和 last_IP 包含同一子网中的最后一个 IP。对于每个循环,我将有一个不同的开始和最后一个 IP。
我正在尝试检查包含所有 IP 的变量并查看每个子网下有多少 IP。
最好的方法是什么?这是一个硬编码的例子:
计数 = 0
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"
count = 0
for arp in arps:
if arp >= start_ip and arp <= end_ip:
count = count + 1
print count
else:
continue
print "Count: ", count
有更好更快的方法吗?
两种方式。简单方法:
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
我可以想到以下两种解决方案。方法一的时间复杂度为O(N)
,方法二的时间复杂度为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))
我有一个 python 脚本,它从 arp table 中获取所有 IP 并将其分配给一个变量。我有 for 循环创建另外两个变量 start_IP 包含子网的第一个 IP 和 last_IP 包含同一子网中的最后一个 IP。对于每个循环,我将有一个不同的开始和最后一个 IP。
我正在尝试检查包含所有 IP 的变量并查看每个子网下有多少 IP。
最好的方法是什么?这是一个硬编码的例子: 计数 = 0
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"
count = 0
for arp in arps:
if arp >= start_ip and arp <= end_ip:
count = count + 1
print count
else:
continue
print "Count: ", count
有更好更快的方法吗?
两种方式。简单方法:
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
我可以想到以下两种解决方案。方法一的时间复杂度为O(N)
,方法二的时间复杂度为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))