【问题标题】:Python: Get local IP-Address used to send IP data to a specific remote IP-AddressPython:获取用于将 IP 数据发送到特定远程 IP 地址的本地 IP 地址
【发布时间】:2011-11-12 03:46:28
【问题描述】:

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

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

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

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

这只有时有效。目前返回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]

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

【问题讨论】:

    标签: python ip


    【解决方案1】:

    我不得不解决同样的问题一次,并花了相当长的时间试图找到更好的方法,但没有成功。我也是从 gethostname 开始的,但像你一样发现它并不总是返回正确的结果,甚至在主机文件出现问题的情况下会抛出异常。

    我能找到跨平台可靠工作的唯一解决方案是尝试连接,就像你正在做的那样。您的代码的一项改进是使用 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 丢弃端口,因此比一些随机的高编号端口稍微不那么奇怪。

    【讨论】:

    • 啊,甜蜜的同理心!使用SOCK_DGRAM,这将是近乎完美的!但在我的情况下,s.getsockname() 返回('0.0.0.0', 51770)。我试过s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM); s.sendto(b'hello', ('1.2.3.4', 50000)); s.getsockname()[0]。如果您将代码添加到答案中,那就太好了!
    • 效果很好;它甚至使用了我不知道的Discard Protocol!我用with 语句替换了del s
    【解决方案2】:

    发送方是否需要知道其 IP 地址?

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

    【讨论】:

    • 异端!这项服务可以做很多事情,让我的生活更轻松。但是同样的问题也出现在项目中的 SIP 实现中。它必须在REGISTER 请求的Contact 标头中发送自己的IP 地址。
    猜你喜欢
    • 2020-11-29
    • 1970-01-01
    • 2011-10-11
    • 1970-01-01
    • 2018-03-14
    • 2021-10-06
    • 1970-01-01
    • 2021-01-28
    • 2020-07-27
    相关资源
    最近更新 更多