Python:获取用于将IP数据发送到特定远程IP地址的本地IP地址

2024-04-26 07:33:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用Python脚本将UDP数据包发送到服务器,服务器将注册我的脚本以接收来自服务器的通知。协议要求我发送自己的IP地址和接收这些通知的端口,因此这应该是一个可以从服务器网络访问的地址。

解决方案至少应该在WindowsXP和更高版本上工作,最好是MacOSX,因为这是我的开发平台。

第一步是获取我的任何接口的IP地址。我目前正在使用通常建议的方法解析计算机自己的主机名:

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

这只是有时有效。目前它返回172.16.249.1,这是VM软件使用的虚拟接口的地址,所以这是一个问题。

更好的方法是获取默认接口的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超时。有没有更好的方法来获取这些信息?


Tags: to方法服务器脚本协议getreturnserver
2条回答

我不得不解决同一个问题一次,花了相当长的时间试图找到更好的方法,但没有成功。我也从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 discard端口,因此比一些随机的高编号端口稍不奇怪。

发送端需要知道它的IP地址吗?

在发送UDP“register”之后,客户端不能只监听它试图订阅的数据(在所有接口上),而让服务器开始将数据发送到数据报的来源地址吗?

相关问题 更多 >