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


当前回答

@fatal_error解决方案应该是接受的答案!这是他的解决方案在nodejs中的实现,以备人们需要:

const dgram = require('dgram');

async function get_local_ip() {
    const s = new dgram.createSocket('udp4');
    return new Promise((resolve, reject) => {
        try {
            s.connect(1, '8.8.8.8', function () {
                const ip = s.address();
                s.close();
                resolve(ip.address)
            });
        } catch (e) {
            console.error(e);
            s.close();
            reject(e);
        }
    })
}

其他回答

一台计算机可以有多个网络接口(包括您提到的本地环回127.0.0.1)。就操作系统而言,它也是一个“真实IP地址”。

如果你想跟踪所有的接口,看看下面的Python包,参见:http://alastairs-place.net/netifaces/

我认为,如果您从主机文件中删除环回条目,就可以避免gethostbyname返回127.0.0.1。(有待核实)。

对于*nix系统上的IP地址列表,

import subprocess
co = subprocess.Popen(['ifconfig'], stdout = subprocess.PIPE)
ifconfig = co.stdout.read()
ip_regex = re.compile('((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-4]|2[0-5][0-9]|[01]?[0-9][0-9]?))')
[match[0] for match in ip_regex.findall(ifconfig, re.MULTILINE)]

虽然现在回答这个问题有点晚了,但我认为其他人可能会发现它有用:-)

PS:它会返回广播地址和网络掩码。

@fatal_error解决方案应该是接受的答案!这是他的解决方案在nodejs中的实现,以备人们需要:

const dgram = require('dgram');

async function get_local_ip() {
    const s = new dgram.createSocket('udp4');
    return new Promise((resolve, reject) => {
        try {
            s.connect(1, '8.8.8.8', function () {
                const ip = s.address();
                s.close();
                resolve(ip.address)
            });
        } catch (e) {
            console.error(e);
            s.close();
            reject(e);
        }
    })
}

另一个变体的前面的答案,可以保存到一个名为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

Socket API方法

参见https://stackoverflow.com/a/28950776/711085

缺点:

Not cross-platform. Requires more fallback code, tied to existence of particular addresses on the internet This will also not work if you're behind a NAT Probably creates a UDP connection, not independent of (usually ISP's) DNS availability (see other answers for ideas like using 8.8.8.8: Google's (coincidentally also DNS) server) Make sure you make the destination address UNREACHABLE, like a numeric IP address that is spec-guaranteed to be unused. Do NOT use some domain like fakesubdomain.google.com or somefakewebsite.com; you'll still be spamming that party (now or in the future), and spamming your own network boxes as well in the process.


反射器方法

(请注意,这并没有回答OP的本地IP地址问题,例如192.168…;它会给你你的公共IP地址,根据用例,这可能更可取。)

你可以查询一些网站,如whatismyip.com(但有一个API),例如:

from urllib.request import urlopen
import re
def getPublicIp():
    data = str(urlopen('http://checkip.dyndns.com/').read())
    # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'

    return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)

或者如果使用python2:

from urllib import urlopen
import re
def getPublicIp():
    data = str(urlopen('http://checkip.dyndns.com/').read())
    # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'

    return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)

优点:

这种方法的一个优点是它是跨平台的 它从丑陋的nat(例如你的家用路由器)后面工作。

缺点(和变通方法):

要求网站正常运行,格式不变(几乎肯定不会),DNS服务器正常工作。在失败的情况下,还可以通过查询其他第三方IP地址反射器来缓解这个问题。 如果您不查询多个反射器(以防止一个受损害的反射器告诉您您的地址不是某个东西),或者如果您不使用HTTPS(以防止假装是服务器的中间人攻击),则可能的攻击向量


edit: Though initially I thought these methods were really bad (unless you use many fallbacks, the code may be irrelevant many years from now), it does pose the question "what is the internet?". A computer may have many interfaces pointing to many different networks. For a more thorough description of the topic, google for gateways and routes. A computer may be able to access an internal network via an internal gateway, or access the world-wide web via a gateway on for example a router (usually the case). The local IP address that the OP asks about is only well-defined with respect to a single link layer, so you have to specify that ("is it the network card, or the ethernet cable, which we're talking about?"). There may be multiple non-unique answers to this question as posed. However the global IP address on the world-wide web is probably well-defined (in the absence of massive network fragmentation): probably the return path via the gateway which can access the TLDs.