[英]How to efficiently check if a given IP Address belong to an IP subnetwork in Python?
我有一組大約200,000個IP地址和10,000個子網(1.1.1.1/24)。 對於每個IP地址,我需要檢查它是否屬於這些子網之一,但由於它是一個如此龐大的數據集並且我的計算能力較低,我希望能夠有效地實現這一點。
在搜索時,我找到的一種方法就是這個( https://stackoverflow.com/a/820124/7995937 ):
from netaddr import IPNetwork, IPAddress
if IPAddress("192.168.0.1") in IPNetwork("192.168.0.0/24"):
print "Yay!"
但是由於我必須循環這超過200,000個IP地址,並且每個地址循環超過10,000個子網,我不確定這是否有效。 我的第一個疑問是,檢查“IPNetwork()中的IPAddress()”只是線性掃描還是以某種方式優化?
我想出的另一個解決方案是列出包含在IP子網中的所有IP的列表(大約有13,000,000個IP,沒有重復),然后對其進行排序。 如果我這樣做,那么在我的200,000個IP地址的循環中,我只需要通過一組更大的IP地址對每個IP進行二進制搜索。
for ipMasked in ipsubnets: # Here ipsubnets is the list of all subnets
setUnmaskedIPs = [str(ip) for ip in IPNetwork(ipMasked)]
ip_list = ip_list + setUnmaskedIPs
ip_list = list(set(ip_list)) # To eliminate duplicates
ip_list.sort()
然后,我可以按以下方式執行二進制搜索:
for ip in myIPList: # myIPList is the list of 200,000 IPs
if bin_search(ip,ip_list):
print('The ip is present')
這種方法比另一種更有效嗎? 或者還有其他更有效的方法來執行此任務嗎?
這可能不是最好的解決方案,但我建議使用集合而不是列表。 優化集以檢查集合中是否存在任何給定值,因此您將使用單個操作替換二進制搜索。 代替:
ip_list = list(set(ip_list))
做就是了:
ip_set = set(ip_list)
然后你的代碼的另一部分變成:
for ip in myIPList: # myIPList is the list of 200,000 IPs
if ip in ip_set:
print('The ip is present')
編輯:為了使內存更有效,您可以跳過創建中間列表:
ip_set = set()
for ipMasked in ipsubnets:
ip_set.update([str(ip) for ip in IPNetwork(ipMasked)])
好的,所以排序需要O(nlogn),如果是13,000,000你最終做O(13000000log(13000000))。 然后你正在迭代超過200000個IP並在13000000上的排序列表上進行二進制搜索O(logn)。我真誠地懷疑這是最好的解決方案。 我建議你使用地圖
from netaddr import IPNetwork, IPAddress
l_ip_address = map(IPAddress, list_of_ip_address)
l_ip_subnet = map(IPNetwork, list_of_subnets)
if any(x in y for x in l_ip_address for y in l_ip_subnet):
print "FOUND"
如果該地址的N個前導位與其中一個N位子網的N個前導位匹配,則在子網中輸入您的IP地址。 所以,首先列出空集。 將每個子網編碼為32位整數,並將尾隨位屏蔽掉。 例如,1.2.3.4/23等於(0x01020304和0xfffffe00)等於0x01020200。 將此數字添加到列表中的第23個集合,即subnets[23]
。 繼續所有子網。
要查看您的子網中是否有IP地址,請以與32位數字ipaddr
相同的方式對IP地址進行編碼,然后(類似於未經測試的代碼)
for N in range( 32, 0, -1)
mask = ( 0xffffffff >> (32-N) ) << (32-N)
if (ipaddr & mask) in subnets[N] :
# have found ipaddr in one of our subnets
break # or do whatever...
else
# have not found ipaddr
在最壞的O(log N)中查找集合中的數字,其中N在集合中的元素數量中。 對於不在子網集中的IP地址的最壞情況,此代碼最多執行32次。 如果預計大多數地址都存在,那么首先要測試具有最多元素的集合進行優化。 那可能是
for N in ( 24, 16, 8, 29, 23, 28, 27, 26, 25, 22, 15, 21 ... )
或者您可以在運行時計算最佳序列。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.