如何找到本地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);
        }
    })
}

其他回答

这是UnkwnTech的答案的变体——它提供了一个get_local_addr()函数,该函数返回主机的主LAN ip地址。我发布它是因为这增加了一些东西:ipv6支持,错误处理,忽略localhost/linklocal地址,并使用TESTNET地址(rfc5737)来连接。

# imports
import errno
import socket
import logging

# localhost prefixes
_local_networks = ("127.", "0:0:0:0:0:0:0:1")

# ignore these prefixes -- localhost, unspecified, and link-local
_ignored_networks = _local_networks + ("0.", "0:0:0:0:0:0:0:0", "169.254.", "fe80:")

def detect_family(addr):
    if "." in addr:
        assert ":" not in addr
        return socket.AF_INET
    elif ":" in addr:
        return socket.AF_INET6
    else:
        raise ValueError("invalid ipv4/6 address: %r" % addr)

def expand_addr(addr):
    """convert address into canonical expanded form --
    no leading zeroes in groups, and for ipv6: lowercase hex, no collapsed groups.
    """
    family = detect_family(addr)
    addr = socket.inet_ntop(family, socket.inet_pton(family, addr))
    if "::" in addr:
        count = 8-addr.count(":")
        addr = addr.replace("::", (":0" * count) + ":")
        if addr.startswith(":"):
            addr = "0" + addr
    return addr

def _get_local_addr(family, remote):
    try:
        s = socket.socket(family, socket.SOCK_DGRAM)
        try:
            s.connect((remote, 9))
            return s.getsockname()[0]
        finally:
            s.close()
    except socket.error:
        # log.info("trapped error connecting to %r via %r", remote, family, exc_info=True)
        return None

def get_local_addr(remote=None, ipv6=True):
    """get LAN address of host

    :param remote:
        return  LAN address that host would use to access that specific remote address.
        by default, returns address it would use to access the public internet.

    :param ipv6:
        by default, attempts to find an ipv6 address first.
        if set to False, only checks ipv4.

    :returns:
        primary LAN address for host, or ``None`` if couldn't be determined.
    """
    if remote:
        family = detect_family(remote)
        local = _get_local_addr(family, remote)
        if not local:
            return None
        if family == socket.AF_INET6:
            # expand zero groups so the startswith() test works.
            local = expand_addr(local)
        if local.startswith(_local_networks):
            # border case where remote addr belongs to host
            return local
    else:
        # NOTE: the two addresses used here are TESTNET addresses,
        #       which should never exist in the real world.
        if ipv6:
            local = _get_local_addr(socket.AF_INET6, "2001:db8::1234")
            # expand zero groups so the startswith() test works.
            if local:
                local = expand_addr(local)
        else:
            local = None
        if not local:
            local = _get_local_addr(socket.AF_INET, "192.0.2.123")
            if not local:
                return None
    if local.startswith(_ignored_networks):
        return None
    return local

注意:这里没有使用标准库,但是非常简单。

$ PIP安装pif

from pif import get_public_ip
get_public_ip()

这个答案是我个人试图解决获得LAN IP的问题,因为socket.gethostbyname(socket.gethostname())也返回127.0.0.1。这种方法不需要Internet,只需要一个局域网连接。代码是为Python 3编写的。X但是可以很容易地转换为2.x。使用UDP广播:

import select
import socket
import threading
from queue import Queue, Empty

def get_local_ip():
        def udp_listening_server():
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.bind(('<broadcast>', 8888))
            s.setblocking(0)
            while True:
                result = select.select([s],[],[])
                msg, address = result[0][0].recvfrom(1024)
                msg = str(msg, 'UTF-8')
                if msg == 'What is my LAN IP address?':
                    break
            queue.put(address)

        queue = Queue()
        thread = threading.Thread(target=udp_listening_server)
        thread.queue = queue
        thread.start()
        s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s2.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        waiting = True
        while waiting:
            s2.sendto(bytes('What is my LAN IP address?', 'UTF-8'), ('<broadcast>', 8888))
            try:
                address = queue.get(False)
            except Empty:
                pass
            else:
                waiting = False
        return address[0]

if __name__ == '__main__':
    print(get_local_ip())

在Debian上(经过测试),我怀疑大多数Linux ..

import commands

RetMyIP = commands.getoutput("hostname -I")

在MS Windows上(已测试)

import socket

socket.gethostbyname(socket.gethostname())
import socket
print(socket.gethostbyname(socket.getfqdn()))