Реализация ping ICMP для Python при проверке нескольких ips из потоков? - PullRequest
2 голосов
/ 17 января 2012

Я использую jedie's python ping реализацию в Windows. Я могу ошибаться, но при пинге двух компьютеров (A и B) из отдельных потоков ping вернет первый полученный пинг, независимо от источника.

Поскольку это может быть проблема с вилкой джедая, я вернулась к предыдущей версии . (Это версия, которую я собираюсь изучить ниже)

Я добавил строку кода в receive_one_ping: (строка 134 или аналогичная)

recPacket, addr = my_socket.recvfrom(1024) # Existing line
print "dest: {}, recv addr: {}.".format(dest_addr, addr) # New line

Это позволяет нам увидеть адрес получаемого нами пинга. (Должен быть таким же, как и IP-адрес назначения, верно?)

Тестирование:

ping1 () проверяет связь с известным автономным IP-адресом (1.2.3.4),
ping2 () пингует известный IP-адрес в сети (192.168.1.1 - мой маршрутизатор)

>>> from ping import do_one

>>> def ping1():
    print "Offline:", do_one("1.2.3.4",1)

>>> ping1()
Offline: None

>>> def ping2():
    print "Online:", do_one("192.168.1.1",1)

>>> ping2()
Online: dest: 192.168.1.1, recv addr: ('192.168.1.1', 0).
0.000403682590942

Теперь, если мы сделаем их вместе: (Для простоты используем таймер)

>>> from threading import Timer
>>> t1 = Timer(1, ping1)
>>> t2 = Timer(1, ping2)
>>> t1.start(); t2.start()
>>> Offline:Online: dest: 192.168.1.1, recv addr: ('192.168.1.1', 0).dest: 1.2.3.4, recv addr: ('192.168.1.1', 0).

0.0004508952953870.000423517514093

Это немного искажено (из-за того, что печать плохо работает с многопоточностью), так что здесь немного понятнее:

>>> Online: dest: 192.168.1.1, recv addr: ('192.168.1.1', 0).
Offline:dest: 1.2.3.4, recv addr: ('192.168.1.1', 0). # this is the issue - I assume dest should be the same as recv address?

0.000450895295387
0.000423517514093

Мои вопросы:

  1. Может кто-нибудь воссоздать это?

  2. Должен ли пинг вести себя так? Я предполагаю, что нет.

  3. Существует ли существующий ICMP-пинг для python, который не будет иметь такого поведения?
    В качестве альтернативы, можете ли вы подумать о простом исправлении - например, опрос receive_one_ping, пока наш пункт назначения не совпадет с нашим адресом получения?

Редактировать: Я создал проблему на странице python-ping github

1 Ответ

5 голосов
/ 17 января 2012

Это происходит из-за природы ICMP.ICMP не имеет понятия портов, поэтому все ICMP-сообщения принимаются всеми прослушивателями.

Обычным способом устранения неоднозначности является установка уникального идентификатора в ICMP ECHOЗАПРОСИТЕ полезную нагрузку и найдите ее в ответе.Этот код, кажется, делает это, но он использует текущий идентификатор процесса для создания идентификатора.Так как это многопоточный код, они будут совместно использовать идентификатор процесса, и все слушатели в текущем процессе будут думать, что все ответы ECHO - это те, которые они сами отправили!

Вам необходимо изменить переменную ID в do_one(), поэтомучто он уникален для каждого потока.Вам нужно будет изменить эту строку в do_one():

my_ID = os.getpid() & 0xFFFF

Возможно , это будет работать в качестве альтернативы, но в идеале вы должны использовать настоящую 16-битную функцию хеширования:

# add to module header
try:
    from thread import get_ident
except ImportError:
    try:
        from _thread import get_ident
    except ImportError:
        def get_ident():
            return 0

# now in do_one() body:
my_ID = (get_ident() ^ os.getpid()) & 0xFFFF

Я не знаю, есть ли у этого модуля какие-либо другие проблемы с потоками, но он кажется нормальным из беглого экзамена.

Используя реализацию jedie, высделает аналогичное изменение для аргумента конструктора Ping() own_id.Вы можете либо передать идентификатор, который вы знаете как уникальный (как выше), и управлять Ping() объектами самостоятельно, либо вы можете изменить эту строку (110) в конструкторе:

self.own_id = os.getpid() & 0xFFFF

Также см. этот вопрос и ответ и ответ на ветку комментариев для получения дополнительной информации.

...