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

Feu*_*mel 10 python ip

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

解决方案至少应该适用于Windows XP及更高版本,最好是Mac OS X,因为这是我的开发平台.

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

def get_local_address():
    return socket.gethostbyname(socket.gethostname())
Run Code Online (Sandbox Code Playgroud)

这有时只能起作用.目前它返回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]
Run Code Online (Sandbox Code Playgroud)

在服务器无法访问或其间的恶意防火墙阻止ICMP数据包的情况下,这将阻止直到达到某个TCP超时.有没有更好的方法来获取这些信息?

DNS*_*DNS 12

我不得不一次解决同样的问题,并花了相当多的时间试图找到一个更好的方法,但没有成功.我也开始使用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
Run Code Online (Sandbox Code Playgroud)

我认为你得到的是0.0.0.0,因为你在调用getsockname之前关闭套接字.另一个提示是我使用端口9; 它是RFC863 UDP丢弃端口,因此比一些随机高编号端口略微怪异.