4

将 UDP 套接字绑定到("", 1234)or("0.0.0.0", 1234)时,是否可以找出它实际发送的 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 回答 2

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
于 2014-04-04T11:55:38.870 回答
1

这更像是一个通常你不需要的答案。它可能与您的用例不对应。

看看socket.gethostbyname_ex(socket.gethostname())。它显示所有可能的 IP 地址和主机名。您可以从所有这些中接收,因为您没有绑定到其中任何一个。它们将是您的源 IP 地址。

您不必知道您发送的确切地址。如果接收者经过 NAT、进入互联网或通过 VPN,它可能会看到另一个。然后,接收者将知道数据包来自哪里并可以发送答案。

@Joachim_Pileborg 也是对的。通常不这样做。

如果您需要特定的接口,请绑定到它。如果没有,您可能不需要它。

于 2014-04-04T11:05:39.430 回答