简体   繁体   English

从线程ping多个IP时,Python ICMP ping实现?

[英]Python ICMP ping implementation when pinging multiple ips from threads?

I've been using jedie's python ping implementation on Windows. 我一直在Windows上使用jedie的python ping实现 I could be wrong, but when pinging two computers (A and B) from separate threads, ping will return the first ping it receives, regardless of source. 我可能是错的,但是从不同的线程对两台计算机(A和B)执行ping操作时,无论源如何,ping都会返回它收到的第一个ping。

Since it could be an issue with jedie's fork, I reverted to the previous version . 由于这可能是jedie的fork的问题,所以我恢复了以前的版本 (This is the version I'm going to explore below) (这是我将在下面探讨的版本)

I added in a line of code in receive_one_ping : (Line 134 or similar) 我在receive_one_ping添加了一行代码:(第134行或类似代码)

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

This allows us to see the address of the ping we're receiving. 这使我们可以查看收到的ping地址。 (Should be same as the destination IP, right?) (应该与目标IP相同,对吧?)

Testing: 测试:

ping1() pings a known offline IP (1.2.3.4), ping1()对已知的脱机IP(1.2.3.4)进行ping操作,
ping2() pings a known online IP (192.168.1.1 - my router) ping2()ping一个已知的在线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

Now if we do them together: (Using Timer for simplicity) 现在,如果我们一起做它们:(使用Timer来简化操作)

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

It's a little mangled (due to print not working nicely with threading), so here it is a bit clearer: 它有点乱了(由于打印不能很好地与线程配合使用),所以这里有点清晰:

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

My questions: 我的问题:

  1. Can anyone recreate this? 任何人都可以重新创建吗?

  2. Should ping be behaving like this? ping的行为应该如此吗? I assume not. 我认为不是。

  3. Is there an existing ICMP ping for python that will not have this behaviour? 是否有不存在此行为的python的现有ICMP ping?
    Alternatively, can you think of an easy fix - ie polling receive_one_ping until our destination matches our receive address? 或者,您能想到一个简单的解决方法-即轮询receive_one_ping直到我们的目的地与我们的接收地址匹配?

Edit: I've created an issue on the python-ping github page 编辑:我已经在python-ping github页面上创建了一个问题

This is happening because of the nature of ICMP. 这是由于ICMP的性质而发生的。 ICMP has no concept of ports, so all ICMP messages are received by all listeners. ICMP没有端口的概念,因此所有 ICMP消息都被所有侦听器接收。

The usual way to disambiguate is to set a unique identifier in the ICMP ECHO REQUEST payload, and look for it in the response. 消除歧义的通常方法是在ICMP ECHO REQUEST有效负载中设置唯一标识符,然后在响应中寻找它。 This code appears to do that, but it uses the current process id to compose the ID. 该代码似乎可以做到这一点,但是它使用当前进程ID来组成ID。 Since this is multithreaded code, they will share a process id and all listeners in the current process will think all ECHO REPLYs are ones they themselves sent! 由于这是多线程代码,它们将共享一个进程ID,并且当前进程中的所有侦听器都将认为所有ECHO REPLY都是他们自己发送的!

You need to change the ID variable in do_one() so that it is per-thread unique. 您需要在do_one()更改ID变量,以便它是每个线程唯一的。 You will need to change this line in do_one() : 您将需要在do_one()更改此行:

my_ID = os.getpid() & 0xFFFF

Possibly this will work as an alternative, but ideally you should use a real 16-bit hashing function: 可能这可以替代,但理想情况下,您应该使用真正的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

I don't know if this module has any other thread issues, but it seems to be ok from a cursory examination. 我不知道该模块是否还有其他线程问题,但是从粗略的检查来看似乎还可以。

Using the jedie implementation, you would make a similar change for the Ping() own_id constructor argument. 使用jedie实现,您将对Ping() own_id构造函数参数进行类似的更改。 You can either pass in an id you know to be unique (like above) and manage Ping() objects yourself, or you can change this line (110) in the constructor: 您可以传入一个唯一的ID(如上),然后自己管理Ping()对象,也可以在构造函数中更改此行(110):

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

Also see this question and answer and answer comment thread for more info. 另请参阅此问题以及答案和评论注释主题以获取更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM