簡體   English   中英

Python:獲取用於將IP數據發送到特定遠程IP地址的本地IP地址

[英]Python: Get local IP-Address used to send IP data to a specific remote IP-Address

我正在使用Python腳本將UDP數據包發送到服務器,該服務器將注冊我的腳本以接收來自服務器的通知。 該協議要求我發送自己的IP地址和端口,我希望收到這些通知,因此這應該是可以從服務器網絡訪問的地址。

解決方案至少應該適用於Windows XP及更高版本,最好是Mac OS X,因為這是我的開發平台。

第一步是獲取任何接口的IP地址。 我目前正在使用通常建議的解析機器自己的主機名的方法:

def get_local_address():
    return socket.gethostbyname(socket.gethostname())

這有時只能起作用。 目前它返回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]

在服務器無法訪問或其間的惡意防火牆阻止ICMP數據包的情況下,這將阻止直到達到某個TCP超時。 有沒有更好的方法來獲取這些信息?

我不得不一次解決同樣的問題,並花了相當多的時間試圖找到一個更好的方法,但沒有成功。 我也開始使用gethostname,但是你發現它並不總是返回正確的結果,甚至可以在hosts文件出現問題的情況下拋出異常。

我能找到的唯一可以跨平台可靠運行的解決方案是嘗試連接,就像你正在做的那樣。 您的代碼的一個改進是使用UDP而不是TCP,即SOCK_DGRAM而不是SOCK_STREAM。 這避免了連接超時,並且該功能立即完成。

如果要將此代碼部署到可能正在運行防火牆的客戶端位置,請確保記錄它執行此檢查的事實。 否則,他們可能會看到針對端口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

我認為你得到的是0.0.0.0,因為你在調用getsockname之前關閉套接字。 另一個提示是我使用端口9; 它是RFC863 UDP丟棄端口,因此比一些隨機高編號端口略微怪異。

發送方是否需要知道其IP地址?

在發送UDP'寄存器'之后,客戶端是否只能監聽其嘗試訂閱的數據(在所有接口上)並讓服務器開始將數據發送到數據報源自的地址?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM