2011-09-07 11 views
9

Pythonスクリプトを使用してサーバにUDPパケットを送信し、サーバからの通知を受信するスクリプトを登録します。プロトコルでは、これらの通知を受信する自分のIPアドレスとポートを送信する必要があるため、これはサーバーのネットワークから到達可能なアドレスにする必要があります。Python:特定のリモートIPアドレスにIPデータを送信するために使用されるローカルIPアドレスを取得します。

解決策は少なくとも私の開発プラットフォームであるため、Windows XP以上、好ましくはMac OS Xで動作するはずです。

最初の手順は、自分のインターフェイスのIPアドレスを取得することです。私は現在、マシンのホスト名を解決する一般的に提案されている方法を使用しています:

これは時々動作します。現在、172.16.249.1を返します。これは、VM Wareで使用される仮想インターフェイスのアドレスです。したがって、これは問題です。

デフォルトのインターフェイスのIPアドレスを取得する方法は、ほとんどの場合、最も適切な方法です。

さらに、TCPのような接続指向のプロトコルによってサーバーに接続するために使用される実際のIPアドレスを取得する方法があります。私は実際にではなく、接続を開こうとせずに、そのアドレスを取得することができます:

def get_address_to_connect_to(server_addr): 
    non_open_port = 50000 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

    try: 
     s.connect((server_addr, non_open_port)) 
    except socket.error: 
     pass 
    else: 
     s.close() # just in case 

    return s.getsockname()[0] 

いくつかのTCPのタイムアウトはサーバが到達不能である場合には到達しているかの間で邪悪なファイアウォールがICMPをブロックされるまで、これはブロックします。パケット。その情報を入手するより良い方法はありますか?

答えて

11

私は同じ問題を一度解決しなければならず、成功することなくより良い方法を見つけようと多くの時間を費やしました。私もgethostnameを使い始めましたが、あなたがしたように常に正しい結果を返すとは限らず、hostsファイルに問題がある場合に例外をスローすることさえできることを発見しました。

プラットフォーム間で確実に動作する唯一の解決策は、接続を試みることです。コードの改善点の1つは、TCPの代わりにUDP(SOCK_STREAMではなくSOCK_DGRAM)を使用することです。これにより、接続タイムアウトが回避され、関数はただちに完了します。

ファイアウォールを実行している可能性のあるクライアントの場所にこのコードを展開する場合は、このチェックを行うことを文書化してください。そうしないと、ポート50000への発信接続のファイアウォール警告が表示され、その目的を理解できず、バグとみなされる可能性があります。

編集:ここで私が使用したコードは、おおよそです:

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 

try: 
    s.connect((host, 9)) 
    client = s.getsockname()[0] 
except socket.error: 
    client = "Unknown IP" 
finally: 
    del s 
return client 

私はあなたがのgetsocknameを呼び出す前にソケットをクローズしているので、あなたは0.0.0.0を取得していると思います。もう一つのヒントは私のポート9の使用です。それはRFC863のUDP破棄ポートなので、いくつかの乱数の高い番号のポートより少し奇妙です。

+0

ああ、甘い共感! 'SOCK_DGRAM'では、ほぼ完璧です!しかし 's.getsockname()'は私の場合は '(0.0.0.0 '、51770)'を返します。私は 's = socket.socket(socket.AF_INET、socket.SOCK_DGRAM)を試しました。 s.sendto(b'hello '、(' 1.2.3.4 '、50000)); s.getsockname()[0] '。あなたの答えにあなたのコードを追加すれば素晴らしいだろう! – Feuermurmel

+0

私の答えを編集してください。 – DNS

+0

これは完全に機能します。それは私が知らなかった[Discard Protocol](http://en.wikipedia.org/wiki/Discard_Protocol)を使っています!私は 'del s'を' with'ステートメントに置き換えました。 – Feuermurmel

0

送信側はIPアドレスを知る必要がありますか?

クライアントは、UDPレジスタを送信した後に(すべてのインターフェイス上で)加入しようとしているデータをリッスンし、データグラムの発信元アドレスにデータを送信し始めることはできませんか?

+0

異教徒!そのサービスは、私の人生を楽にするために多くのことを行うことができます。しかし、同じ問題がSIP実装にも現れますが、これもプロジェクトの一部です。それは 'REGISTER'要求の' Contact'ヘッダにそれ自身のIPアドレスを送信しなければなりません。 – Feuermurmel

関連する問題