使用Python查找本地IP地址';s标准数据库

使用Python查找本地IP地址';s标准数据库,python,networking,ip-address,Python,Networking,Ip Address,如何在Python平台中独立地并且仅使用标准库查找本地IP地址(即192.168.x.x或10.0.x.x) import socket socket.gethostbyname(socket.gethostname()) 这并不总是有效(在主机名位于/etc/hosts中的计算机上,返回127.0.0.1作为127.0.0.1),gimel显示的是一个反义词,使用socket.getfqdn()。当然,您的计算机需要一个可解析的主机名。恐怕除了连接到另一台计算机并让它向您发送IP地址之外,没

如何在Python平台中独立地并且仅使用标准库查找本地IP地址(即192.168.x.x或10.0.x.x)

import socket
socket.gethostbyname(socket.gethostname())

这并不总是有效(在主机名位于
/etc/hosts
中的计算机上,返回
127.0.0.1
作为
127.0.0.1
),gimel显示的是一个反义词,使用
socket.getfqdn()
。当然,您的计算机需要一个可解析的主机名。

恐怕除了连接到另一台计算机并让它向您发送IP地址之外,没有任何与平台无关的好方法。例如:。请注意,如果您需要NAT后面的IP地址,除非您连接的计算机也在NAT后面,否则这将不起作用


这里有一个在Linux中有效的解决方案:。

我刚刚找到了这个解决方案,但它似乎有点黑客化,不过他们说我在*nix上试过,在windows上也试过,效果很好

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
print(s.getsockname()[0])
s.close()
这假设您可以访问internet,并且没有本地代理。

您可以使用该模块。仅键入:

pip install netifaces
在命令shell中,它将在默认Python安装中自行安装

然后你可以这样使用它:

from netifaces import interfaces, ifaddresses, AF_INET
for ifaceName in interfaces():
    addresses = [i['addr'] for i in ifaddresses(ifaceName).setdefault(AF_INET, [{'addr':'No IP addr'}] )]
    print '%s: %s' % (ifaceName, ', '.join(addresses))
在我的电脑上,它打印了:

{45639BDC-1050-46E0-9BE9-075C30DE1FBC}: 192.168.0.100 {D43A468B-F3AE-4BF9-9391-4863A4500583}: 10.5.9.207 {45639BDC-1050-46E0-9BE9-075C30DE1FBC}:192.168.0.100 {D43A468B-F3AE-4BF9-9391-4863A4500583}:10.5.9.207
本模块的作者声称它应该在Windows、UNIX和Mac OS X上工作。

如果您不想使用外部软件包,也不想依赖外部Internet服务器,这可能会有所帮助。这是我在上找到并修改的代码示例,用于返回所需信息:

def getIPAddresses():
    from ctypes import Structure, windll, sizeof
    from ctypes import POINTER, byref
    from ctypes import c_ulong, c_uint, c_ubyte, c_char
    MAX_ADAPTER_DESCRIPTION_LENGTH = 128
    MAX_ADAPTER_NAME_LENGTH = 256
    MAX_ADAPTER_ADDRESS_LENGTH = 8
    class IP_ADDR_STRING(Structure):
        pass
    LP_IP_ADDR_STRING = POINTER(IP_ADDR_STRING)
    IP_ADDR_STRING._fields_ = [
        ("next", LP_IP_ADDR_STRING),
        ("ipAddress", c_char * 16),
        ("ipMask", c_char * 16),
        ("context", c_ulong)]
    class IP_ADAPTER_INFO (Structure):
        pass
    LP_IP_ADAPTER_INFO = POINTER(IP_ADAPTER_INFO)
    IP_ADAPTER_INFO._fields_ = [
        ("next", LP_IP_ADAPTER_INFO),
        ("comboIndex", c_ulong),
        ("adapterName", c_char * (MAX_ADAPTER_NAME_LENGTH + 4)),
        ("description", c_char * (MAX_ADAPTER_DESCRIPTION_LENGTH + 4)),
        ("addressLength", c_uint),
        ("address", c_ubyte * MAX_ADAPTER_ADDRESS_LENGTH),
        ("index", c_ulong),
        ("type", c_uint),
        ("dhcpEnabled", c_uint),
        ("currentIpAddress", LP_IP_ADDR_STRING),
        ("ipAddressList", IP_ADDR_STRING),
        ("gatewayList", IP_ADDR_STRING),
        ("dhcpServer", IP_ADDR_STRING),
        ("haveWins", c_uint),
        ("primaryWinsServer", IP_ADDR_STRING),
        ("secondaryWinsServer", IP_ADDR_STRING),
        ("leaseObtained", c_ulong),
        ("leaseExpires", c_ulong)]
    GetAdaptersInfo = windll.iphlpapi.GetAdaptersInfo
    GetAdaptersInfo.restype = c_ulong
    GetAdaptersInfo.argtypes = [LP_IP_ADAPTER_INFO, POINTER(c_ulong)]
    adapterList = (IP_ADAPTER_INFO * 10)()
    buflen = c_ulong(sizeof(adapterList))
    rc = GetAdaptersInfo(byref(adapterList[0]), byref(buflen))
    if rc == 0:
        for a in adapterList:
            adNode = a.ipAddressList
            while True:
                ipAddr = adNode.ipAddress
                if ipAddr:
                    yield ipAddr
                adNode = adNode.next
                if not adNode:
                    break
用法:

>>> for addr in getIPAddresses():
>>>    print addr
192.168.0.100
10.5.9.207

由于它依赖于Windell,因此只能在Windows上使用。

作为名为
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])'"
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])
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])
  • 可与Python2.x、Python3.x、现代和旧Linux发行版、OSX/macOS和Windows正确配合使用,以查找当前IPv4地址
  • 对于具有多个IP地址、IPv6、没有配置IP地址或没有internet访问的计算机,将不会返回正确的结果
  • 据报道,这在最新版本的macOS上不起作用
注意:如果您打算在Python程序中使用类似的东西,正确的方法是使用支持IPv6的Python模块


与上面相同,但仅Python代码:

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])'"
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])
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])
  • 如果没有配置IP地址,这将引发异常

也可在没有internet连接的LAN上工作的版本:

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])'"
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])
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])
(谢谢)


背景

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

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

导入套接字
打印([socket.gethostbyname_ex(socket.gethostname())[2]中的ip,如果不是ip.startswith(“127”)[:1])
这适用于Linux和Windows上的Python 2和3,但不适用于多个网络设备或IPv6。然而,它在最近的Linux发行版上停止了工作,所以我尝试了这种替代技术。它试图连接到位于
8.8.8.8
端口
53
的Google DNS服务器:

导入套接字
在[socket.socket(socket.AF_INET,socket.SOCK_DGRAM)][0][1]中为s打印([(s.connect(('8.8.8.8',53))、s.getsockname()[0],s.close())
然后,我将上述两种技术组合成一个可以在任何地方使用的一行程序,并在这个答案的顶部创建了
myip
alias和Python代码段


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

im使用以下模块:

#!/usr/bin/python
# module for getting the lan ip address of the computer

import os
import socket

if os.name != "nt":
    import fcntl
    import struct
    def get_interface_ip(ifname):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(fcntl.ioctl(
                s.fileno(),
                0x8915,  # SIOCGIFADDR
                struct.pack('256s', bytes(ifname[:15], 'utf-8'))
                # Python 2.7: remove the second argument for the bytes call
            )[20:24])

def get_lan_ip():
    ip = socket.gethostbyname(socket.gethostname())
    if ip.startswith("127.") and os.name != "nt":
        interfaces = ["eth0","eth1","eth2","wlan0","wlan1","wifi0","ath0","ath1","ppp0"]
        for ifname in interfaces:
            try:
                ip = get_interface_ip(ifname)
                break;
            except IOError:
                pass
    return ip
使用windows和linux进行测试(不需要额外的模块) 用于单个基于IPv4的LAN中的系统

接口名称的固定列表不适用于最新的linux版本,正如所指出的,这些版本采用了systemd v197关于可预测接口名称的更改。
在这种情况下,您需要手动将列表替换为系统上的接口名称,或使用其他解决方案,如。

FYI我可以验证该方法:

import socket
addr = socket.gethostbyname(socket.gethostname())
在OS X(10.6,10.5)、Windows XP和管理良好的RHEL department服务器上工作。它在一个非常小的CentOS虚拟机上不起作用,我只是对它进行了一些内核攻击。因此,对于该实例,您只需检查127.0.0.1地址,在这种情况下,请执行以下操作:

if addr == "127.0.0.1":
     import commands
     output = commands.getoutput("/sbin/ifconfig")
     addr = parseaddress(output)

然后从输出中解析ip地址。应该注意的是,默认情况下ifconfig不在普通用户的路径中,这就是我在命令中给出完整路径的原因。我希望这有帮助。

我在我的ubuntu机器上使用它:

import commands
commands.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:]
这不起作用。

通过命令行utils生成“干净”输出的一种简单方法:

import commands
ips = commands.getoutput("/sbin/ifconfig | grep -i \"inet\" | grep -iv \"inet6\" | " +
                         "awk {'print $2'} | sed -ne 's/addr\:/ /p'")
print ips
它将显示系统上的所有IPv4地址。

127.0.1.1
是您的真实IP地址。更一般地说,一台计算机可以有任意数量的IP地址。您可以针对专用网络对其进行筛选—127.0.0.0/8、10.0.0.0/8、172.16.0.0/12和192.168.0.0/16


但是,没有跨平台的方法来获取所有IP地址。在Linux上,您可以使用ioctl。

套接字API方法

缺点:

  • 不要跨平台
  • 需要更多回退代码,与internet上特定地址的存在相关
  • 如果您支持NAT,这也不起作用
  • 可能会创建UDP连接,而不是独立于(通常是ISP的)DNS可用性(有关使用8.8.8.8:Google的想法,请参阅其他答案)
    import socket
    [i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]
    
    from pif import get_public_ip
    get_public_ip()
    
    #! /usr/bin/env python
    
    import sys , pynotify
    
    if sys.version_info[1] != 7:
       raise RuntimeError('Python 2.7 And Above Only')       
    
    from subprocess import check_output # Available on Python 2.7+ | N/A 
    
    IP = check_output(['ip', 'route'])
    Split_Result = IP.split()
    
    # print Split_Result[2] # Remove "#" to enable
    
    pynotify.init("image")
    notify = pynotify.Notification("Ip", "Server Running At:" + Split_Result[2] , "/home/User/wireless.png")    
    notify.show()    
    
    easy_install py-notify
    
    pip install py-notify
    
    from pip import main
    
    main(['install', 'py-notify'])
    
    # 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
    
    import socket
    def getNetworkIp():
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        s.connect(('<broadcast>', 0))
        return s.getsockname()[0]
    
    print (getNetworkIp())
    
    import netifaces
    
    PROTO = netifaces.AF_INET   # We want only IPv4, for now at least
    
    # Get list of network interfaces
    # Note: Can't filter for 'lo' here because Windows lacks it.
    ifaces = netifaces.interfaces()
    
    # Get all addresses (of all kinds) for each interface
    if_addrs = [netifaces.ifaddresses(iface) for iface in ifaces]
    
    # Filter for the desired address type
    if_inet_addrs = [addr[PROTO] for addr in if_addrs if PROTO in addr]
    
    iface_addrs = [s['addr'] for a in if_inet_addrs for s in a if 'addr' in s]
    # Can filter for '127.0.0.1' here.
    
    import netifaces
    
    PROTO = netifaces.AF_INET   # We want only IPv4, for now at least
    
    # Get list of network interfaces
    ifaces = netifaces.interfaces()
    
    # Get addresses for each interface
    if_addrs = [(netifaces.ifaddresses(iface), iface) for iface in ifaces]
    
    # Filter for only IPv4 addresses
    if_inet_addrs = [(tup[0][PROTO], tup[1]) for tup in if_addrs if PROTO in tup[0]]
    
    iface_addrs = [(s['addr'], tup[1]) for tup in if_inet_addrs for s in tup[0] if 'addr' in s]
    
    from __future__ import print_function  # For 2.x folks
    from pprint import pprint as pp
    
    print('\nifaces = ', end='')
    pp(ifaces)
    
    print('\nif_addrs = ', end='')
    pp(if_addrs)
    
    print('\nif_inet_addrs = ', end='')
    pp(if_inet_addrs)
    
    print('\niface_addrs = ', end='')
    pp(iface_addrs)
    
    import commands
    
    RetMyIP = commands.getoutput("hostname -I")
    
    import socket
    
    socket.gethostbyname(socket.gethostname())
    
    import socket
    
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.connect(('8.8.8.8', 1))  # connect() for UDP doesn't send packets
    local_ip_address = s.getsockname()[0]
    
    import socket
    import fcntl
    import struct
    
    def get_ip_address(ifname):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(fcntl.ioctl(
            s.fileno(),
            0x8915,  # SIOCGIFADDR
            struct.pack('256s', ifname[:15])
        )[20:24])
    
    >>> get_ip_address('eth0')
    '38.113.228.130'
    
    import socket
    def get_ip():
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        try:
            # doesn't even have to be reachable
            s.connect(('10.255.255.255', 1))
            IP = s.getsockname()[0]
        except Exception:
            IP = '127.0.0.1'
        finally:
            s.close()
        return IP
    
    async get_local_ip():
        loop = asyncio.get_event_loop()
        transport, protocol = await loop.create_datagram_endpoint(
            asyncio.DatagramProtocol,
            remote_addr=('8.8.8.8', 80))
        result = transport.get_extra_info('sockname')[0])
        transport.close()
        return result
    
    import netifaces as ni 
    
    ni.ifaddresses('eth0')
    ip = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
    print(ip)
    
    import subprocess
    address = subprocess.check_output(['hostname', '-s', '-I'])
    address = address.decode('utf-8') 
    address=address[:-1]
    
    address = subprocess.check_output(['hostname', '-s', '-I']).decode('utf-8')[:-1]
    
    from subprocess import check_output
    check_output(['hostname', '-I'])