Python - лучший способ подсчета IP-адресов, попадающих в диапазон IP-адресов - PullRequest
0 голосов
/ 20 декабря 2018

У меня есть скрипт на python, который захватывает все IP из таблицы arp и присваивает его переменной.У меня есть цикл, который создает еще две переменные start_IP, содержащий первый IP-адрес подсети и last_IP, содержащий последний IP-адрес в той же подсети.Для каждого цикла у меня будут разные начальный и последний IP-адреса.

Я пытаюсь проверить переменную, содержащую все IP-адреса, и посмотреть, сколько IP-адресов попадает в каждую подсеть.

Каков наилучший способ сделать это?Вот пример в жестком коде: count = 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

Есть ли лучший способ сделать это быстрее?

Ответы [ 2 ]

0 голосов
/ 20 декабря 2018

Я могу думать о двух решениях, как показано ниже.Метод 1 имеет временную сложность O(N), а метод 2 имеет временную сложность O(Nlog N).Как предлагает Амадан, 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))
0 голосов
/ 20 декабря 2018

Два пути.Простой способ:

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
...