在绑定到0.0.0.0时如何查找源IP地址
当我把一个UDP套接字绑定到 ("", 1234)
或 ("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中以可靠的方式获取这个地址吗?
2 个回答
这其实是一个通常情况下你不需要知道的答案。可能和你的情况不太相关。
你可以看看 socket.gethostbyname_ex(socket.gethostname())
。这个命令会显示所有可能的IP地址和主机名。因为你没有绑定到某个特定的IP地址,所以你可以从这些地址中接收数据。它们就是你的源IP地址。
你并不需要知道你发送数据时的确切地址。如果数据经过NAT(网络地址转换)、进入互联网或者通过VPN,接收方可能会看到另一个地址。接收方会知道数据包是从哪里来的,并可以发送回复。
@Joachim_Pileborg 说得也对。通常情况下,这种做法并不常见。
如果你需要指定某个网络接口,就绑定到它。如果不需要,那你可能根本不需要这样做。
当你发送数据包时,使用的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