如何找到本地IP地址(即192.168.x。x或10.0.x.x)在Python平台独立,只使用标准库?


当前回答

import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]

其他回答

作为别名myip:

alias myip="python -c 'import socket; print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith(\"127.\")][:1], [[(s.connect((\"8.8.8.8\", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])'"

适用于Python 2。3. Python。x,现代和旧的Linux发行版,OSX/macOS和Windows来查找当前的IPv4地址。 对于有多个IP地址、IPv6、没有配置IP地址或没有互联网访问的机器,将不会返回正确的结果。 据报道,这在最新版本的macOS上不起作用。

注意:如果你打算在Python程序中使用类似的东西,正确的方法是使用支持IPv6的Python模块。


与上面相同,但只是Python代码:

import socket
print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1], [[(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])

如果没有配置IP地址,将抛出异常。


也可以在没有互联网连接的局域网上工作的版本:

import socket
print((([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")] or [[(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) + ["no IP found"])[0])

(谢谢@ccpizza)


背景:

使用socket.gethostbyname(socket.gethostname())在这里不起作用,因为我所在的一台计算机有一个/etc/hosts,其中有重复的条目和对自身的引用。Socket.gethostbyname()只返回/etc/hosts.中的最后一项

这是我最初的尝试,它清除了所有以“127”开头的地址。”:

import socket
print([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1])

这适用于Python 2和3,在Linux和Windows上,但不能处理多个网络设备或IPv6。然而,它在最近的Linux发行版上停止工作,所以我尝试了这种替代技术。它尝试在53端口8.8.8.8连接谷歌DNS服务器:

import socket
print([(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1])

然后,我将上述两种技术组合成一个应该在任何地方都适用的一行程序,并在这个答案的顶部创建了myip别名和Python代码片段。

随着IPv6的日益普及,对于具有多个网络接口的服务器,使用第三方Python模块查找IP地址可能比这里列出的任何方法都更健壮和可靠。

我必须解决“判断一个IP地址是否是本地的”这个问题,我的第一个想法是建立一个本地IP列表,然后与之匹配。这让我想到了这个问题。然而,我后来意识到有一种更直接的方法:尝试绑定该IP,看看它是否有效。

_local_ip_cache = []
_nonlocal_ip_cache = []
def ip_islocal(ip):
    if ip in _local_ip_cache:
        return True
    if ip in _nonlocal_ip_cache:
        return False
    s = socket.socket()
    try:
        try:
            s.bind((ip, 0))
        except socket.error, e:
            if e.args[0] == errno.EADDRNOTAVAIL:
                _nonlocal_ip_cache.append(ip)
                return False
            else:
                raise
    finally:
        s.close()
    _local_ip_cache.append(ip)
    return True

我知道这并不能直接回答问题,但是这对于任何试图解决相关问题的人以及遵循相同思路的人都是有帮助的。我认为这是一个跨平台的解决方案。

另一个变体的前面的答案,可以保存到一个名为my-ip-to的可执行脚本:

#!/usr/bin/env python

import sys, socket

if len(sys.argv) > 1:
    for remote_host in sys.argv[1:]:
        # determine local host ip by outgoing test to another host
        # use port 9 (discard protocol - RFC 863) over UDP4
        with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
            s.connect((remote_host, 9))
            my_ip = s.getsockname()[0]
            print(my_ip, flush=True)
else:
    import platform

    my_name = platform.node()
    my_ip = socket.gethostbyname(my_name)
    print(my_ip)

它需要任意数量的远程主机,并打印出本地ip,逐个到达它们:

$ my-ip-to z.cn g.cn localhost
192.168.11.102
192.168.11.102
127.0.0.1
$

并在没有给出arg时打印best-bet。

$ my-ip-to
192.168.11.102
import socket
socket.gethostbyname(socket.getfqdn())

简单而甜蜜!

def getip():

    import socket
    hostname= socket.gethostname()
    ip=socket.gethostbyname(hostname)

    return(ip)