2

Windowsでjedieのpythonping実装を使用しています。私が間違っている可能性もありますが、2 台のコンピューター (A と B) に別々のスレッドから ping を実行すると、ソースに関係なく、ping は最初に受信した ping を返します。

ジェダイのフォークの問題かもしれないので、前のバージョンに戻しました。(これは、以下で調査するバージョンです)

次のコード行に追加しましたreceive_one_ping: (134 行目など)

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

これにより、受信している ping のアドレスを確認できます。(宛先IPと同じはずですよね?)

テスト:

ping1() は既知のオフライン IP (1.2.3.4) に
ping を実行し、ping2() は既知のオンライン IP (192.168.1.1 - 私のルーター) に ping を実行します。

>>> 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. ping はこのように動作する必要がありますか? 私はそうではないと思います。

  3. この動作を行わない Python 用の既存の ICMP ping はありますか?
    または、簡単な修正方法を考えていただけますか?つまりreceive_one_ping、送信先が受信アドレスと一致するまでポーリングすることはできますか?

編集: python-ping github ページに問題を作成しました

4

1 に答える 1

5

これは、ICMP の性質によるものです。ICMP にはポートの概念がないため、すべてのICMP メッセージがすべてのリスナーによって受信されます。

あいまいさを解消する通常の方法は、ICMP ECHO REQUEST ペイロードに一意の識別子を設定し、応答でそれを探すことです。このコードはそうしているように見えますが、現在のプロセス ID を使用して ID を構成しています。これはマルチスレッド コードであるため、プロセス ID を共有し、現在のプロセスのすべてのリスナーは、すべての ECHO REPLY が自分自身が送信したものであると認識します。

スレッドごとに一意になるように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コンストラクターの引数に同様の変更を加えることができます。一意であることがわかっている ID (上記のように) を渡してPing()自分でオブジェクトを管理するか、コンストラクターでこの行 (110) を変更できます。

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

詳細については、この質問と回答と回答のコメント スレッドも参照してください。

于 2012-01-17T03:06:37.777 に答える