2014-04-04 41 views
4

將UDP套接字綁定到("", 1234)("0.0.0.0", 1234)時,是否可以找出它實際發送的IP地址?當綁定到0.0.0.0時查找源IP地址

正如你在下面的代碼中看到的,getsockname只告訴我我要綁定什麼。但是當我發送一個數據包時,我可以看到IP地址在我的情況下是10.0.0.2

我是否必須通過查看我的網絡接口來自己推斷此地址?如果是這樣,那很好,但有沒有一種強有力的方式呢?

from socket import * 
s = socket(AF_INET, SOCK_DGRAM) 
s.bind(("", 1234)) 
print(s.getsockname()) # prints ("0.0.0.0", 1234) 
s.sendto("hello", ("10.0.0.3", 1234)) # sends from 10.0.0.2 

我試着做

import socket 
print(socket.gethostbyname(socket.gethostname())) 

,但似乎並不非常可靠的(在我的預期10.0.0.2的情況下,我得到了127.0.1.1)。

我意識到通過綁定到0.0.0.0,我綁定到全部本地網絡接口。這是否意味着當我嘗試發送內容時,我的源IP地址將由路由表確定?如果是這樣,我仍然可以從Python中以強大的方式獲得該地址嗎?

+4

通過綁定到您可以從所有接口接收的所有接口。發送時,數據包將從數據包發送的實際接口獲取其源設置。您可能必須手動檢查路由表以瞭解將用於特定地址的接口。 –

回答

2

發送時使用的IP地址將由數據包發送時的路由表決定。 可能存在查詢該路由表的平臺特定方式,但相當便攜的方式是先連接()套接字( )。

您也可以使用另一個套接字來查詢這些信息。例如

from socket import * 
s = socket(AF_INET, SOCK_DGRAM) 
s.bind(("", 1234)) 
print(s.getsockname()) # prints ("0.0.0.0", 1234) 
sq = socket(AF_INET, SOCK_DGRAM) 
sq.connect(("10.0.0.3", 1234)) 
print(sq.getsockname()[0]) 
sq.close() 
s.sendto("hello", ("10.0.0.3", 1234)) # sends from 10.0.0.2 
+0

巧妙,它的作品!只有一個問題,最後一個sendto是否有目的?似乎連接和調用'getsockname'是我所需要的。謝謝! – csl

+1

@csl這只是你的例子,用你的sendto(),但使用2. socket來查詢信息。如果您只發送到1個目的地,則可以使用1個套接字並連接該套接字。但是,一旦連接,就不能在該套接字上發送/接收任何其他主機/端口組合的數據包。 – nos

1

這是一個通常你不需要的答案。它可能不符合你的用例。

已登錄socket.gethostbyname_ex(socket.gethostname())。它顯示了所有可能的IP地址和主機名。你可以從所有這些接收,因爲你沒有綁定到任何特定的那些。他們將成爲您的源IP地址。

您不需要知道您發送的確切地址。接收者可能會看到另一個,如果它落後於NAT,進入互聯網或通過VPN。 接收方將知道數據包來自哪裏並可以發送答案。

@Joachim_Pileborg也是對的。這通常不會完成。

如果你需要一個特定的接口,綁定到它。如果沒有,你可能不需要它。

+0

它幾乎可以工作。 'ifconfig'表示有兩個接口:'h1-eth0',IP地址爲10.0.0.3,'lo'爲127.0.0.1。代碼片段返回'('mininet-vm',[],['127.0.1.1'])''。也許這是最好的,我可以做,而不訴諸ifconfig?我一定會看到這個問題,爲什麼我永遠無法確定(就像你說的,在NAT的情況下)。 – csl

+0

爲什麼在I地址列表中沒有'「10.0.0.3」?現在我很困惑。我會期望它列出所有的IP地址。至少,它在Windows下。如果你真的想找出使用​​哪個接口,你應該評論一下。那麼額外答案的可行性就更高了。 – User

+0

我在錯誤的主機上運行了它,但唯一的區別是'ifconfig'在正確的主機(問題示例中使用的那個)上爲'h0-eth0'接口返回10.0.0.2。但是該腳本仍然返回該接口的空地址,看起來(與第一個註釋完全相同的輸出)。我在mininet下運行,這是一個虛擬網絡的網絡模擬器,但只要ifconfig工作,我不認爲應該說什麼。 – csl