使用Python的stdlib查找本地IP地址

Unk*_*ech 514 python networking ip-address

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

Unk*_*ech 436

我刚发现这个,但它看起来有点hackish,但是他们说在*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()
Run Code Online (Sandbox Code Playgroud)

这假设您具有Internet访问权限,并且没有本地代理.

  • 最好使用IP地址而不是域名 - 它必须更快,独立于DNS可用性.例如,我们可以使用8.8.8.8 IP - Google的公共DNS服务器. (38认同)
  • 如果您在机器上有多个接口,并且需要路由到例如gmail.com的接口,那就太好了 (28认同)
  • 很聪明,效果很好.如果适用,您还可以使用要从中查看的服务器的IP或地址,而不是gmail或8.8.8.8. (9认同)
  • 好的,这种方法在Linux和Windows上都能正常工作 (6认同)
  • 捕获可能由s.connect()引发的socket.error异常可能是个好主意! (4认同)
  • 此示例具有能够实际解析gmail.com的外部依赖性.如果将其设置为不在本地LAN上的IP地址(无论是向上还是向下)都没有依赖性且没有网络流量. (3认同)

Vin*_*vic 415

import socket
socket.gethostbyname(socket.gethostname())
Run Code Online (Sandbox Code Playgroud)

这总是不起作用(127.0.0.1在主机/etc/hosts名为as的机器上返回127.0.0.1),gimel显示的是paliative,socket.getfqdn()而是使用.当然,您的机器需要可解析的主机名.

  • 这似乎只返回一个IP地址.如果机器有多个地址怎么办? (54认同)
  • 应该注意,这不是一个独立于平台的解决方案.许多Linux将使用此方法返回127.0.0.1作为您的IP地址. (40认同)
  • 在Ubuntu上,由于某种原因返回127.0.1.1. (25认同)
  • 变体:socket.gethostbyname(socket.getfqdn()) (19认同)
  • @Jason R. Coombs,使用以下代码检索属于主机的IPv4地址列表:`socket.gethostbyname_ex(socket.gethostname())[ - 1]` (11认同)
  • @UnkwnTech请不要接受答案,这显然是不可靠的. (5认同)
  • @Reinis I:在Ubuntu上,由于/ etc/hosts中的一行,它返回127.0.1.1.这条线可以移除而不会产生可怕的后果. (3认同)
  • @amarillion:在某些Ubuntu系统上[哪些?]如果127.0.1.1不在hosts文件中,用户可能会失去运行'sudo'命令的能力.我已经发生了这种情况,并且有记录. (3认同)
  • @amarillion我发现如果/ etc/hosts中缺少这一行,rabbitmq会感到不快 (2认同)
  • 在Windows上也可能是一个问题因为我有VirtualBox,它安装了自己的网络适配器.命令`socket.gethostbyname(socket.gethostname())`返回了Virtualbox地址.@JasonR.Coombs的答案很有帮助,因为它返回了两者.VirtualBox是我的第一个,但我不知道它是如何决定订单的 (2认同)
  • 在 Ubuntu 17.10 上,甚至 @gimel 的答案也返回“127.0.0.1” (2认同)
  • 返回“127.0.0.1” (2认同)

Jam*_*ker 202

此方法返回本地框(具有默认路由的IP)上的"主"IP.

  • 不需要可路由的网络访问或任何连接.
  • 即使从网络上拔下所有接口,也能正常工作.
  • 不需要甚至尝试去其他任何地方.
  • 适用于NAT,公共,私有,外部和内部IP
  • 纯Python 2(或3)没有外部依赖.
  • 适用于Linux,Windows和OSX.

Python 2或3:

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:
        IP = '127.0.0.1'
    finally:
        s.close()
    return IP
Run Code Online (Sandbox Code Playgroud)

这将返回一个主要的IP(具有默认路由的IP).如果您需要将所有IP连接到所有接口(包括localhost等),请参阅此答案.

如果你在家里的wifi防火墙之后就像NAT防火墙一样,那么这将不会显示你的公共NAT IP,而是显示本地网络上的私有NAT IP,它具有到本地WIFI路由器的默认路由; 获取你的无线路由器的外部IP要么需要在这个盒子上运行,要么连接到可以反映IP的外部服务,例如whatismyip.com/whatismyipaddress.com ......但这与原始问题完全不同.:)

在评论中根据Pedro的建议更新了connect()调用.(如果您需要特定的许可声明,这是公共域/免费用于任何用途,或者根据您选择的Stack Overflow代码/内容许可证的MIT/CC2-BY-SA.)

  • 使用Python 2和3在Raspbian中工作! (6认同)
  • 这应该是公认的答案.`socket.gethostbyname(socket.gethostname())`给出了可怕的结果. (5认同)
  • 出于某种原因,这在Mac OS X El Capitan 10.11.6上不起作用(它会生成异常操作系统错误:[Errno 49]无法分配请求的地址).将端口从"0"更改为"1":s.connect(('10.255.255.255',1))在Mac OS X和Linux上都适用于Ubuntu 17.04 (3认同)
  • 在 Ubuntu 22.04 上,我遇到了“权限被拒绝”异常 (3认同)
  • @Bram,很好,无法再连接到广播地址:( 也许现在用 10.254.254.254 尝试一下(不必是真实的 IP)。谢谢! (3认同)
  • 辉煌.适用于Win7,8,8.1 + Linux Mint&Arch,包括VM. (2认同)
  • 适用于Windows 10 Pro!谢谢你,Jamieson Becker! (2认同)

Ale*_*der 142

作为别名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])'"
Run Code Online (Sandbox Code Playgroud)
  • 适用于Python 2.x,Python 3.x,现代和旧版Linux发行版,OSX/macOS和Windows,用于查找当前的IPv4地址.
  • 对于具有多个IP地址,IPv6,未配置IP地址或无法访问Internet的计算机,将无法返回正确的结果.

与上面相同,但只有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])
Run Code Online (Sandbox Code Playgroud)
  • 如果未配置IP地址,则会引发异常.

在没有互联网连接的LAN上也可以使用的版本:

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])
Run Code Online (Sandbox Code Playgroud)

(谢谢@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])
Run Code Online (Sandbox Code Playgroud)

这适用于Linux和Windows上的Python 2和3,但不涉及多个网络设备或IPv6.但是,它停止了最近的Linux发行版,所以我尝试了这种替代技术.它尝试连接到8.8.8.8端口的Google DNS服务器53:

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])
Run Code Online (Sandbox Code Playgroud)

然后我将上述两种技术组合成一个应该在任何地方工作的单行程,并在myip此答案的顶部创建了别名和Python片段.

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

  • 只是因为你可以在一行上编写代码,这并不意味着你应该...... (10认同)
  • "更新"显示了UDP套接字上的connect()的一个很好的技巧.它不发送任何流量,但可以让您找到指定收件人的数据包的发件人地址.端口可能无关紧要(甚至0应该工作).在多宿主主机上,选择正确子网中的地址非常重要. (4认同)
  • @Alexander:只是说这个答案没有以前那么有用了(而且它不像过滤掉重复数据是一件大事;).根据文档`socket.getaddrinfo()`应该跨平台一致地工作 - 但我只在Linux上检查它,没有打扰任何其他操作系统. (2认同)
  • 我可以确认更新版本适用于Ubuntu 14.04,包括Python2和Py3k. (2认同)

Dzi*_*inX 87

您可以使用netifaces模块.只需输入:

pip install netifaces
Run Code Online (Sandbox Code Playgroud)

在命令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))
Run Code Online (Sandbox Code Playgroud)

在我的电脑上打印:

{45639BDC-1050-46E0-9BE9-075C30DE1FBC}: 192.168.0.100
{D43A468B-F3AE-4BF9-9391-4863A4500583}: 10.5.9.207

该模块的作者声称它应该适用于Windows,UNIX和Mac OS X.

  • 正如问题中所述,我想从默认安装中获得一些东西,因为不需要额外的安装. (19认同)
  • 这将是我最喜欢的答案,除了netifaces在Windows上不支持IPv6并且看起来没有维护.有没有人想出如何在Windows上获取IPv6地址? (4认同)
  • @MattJoiner这两件事都不再适用(最新版本在PyPI上有Windows二进制文件,并支持Py3K). (4认同)
  • @ Jean-PaulCalderone FWIW,最新版本的netifaces*确实*在Windows上支持IPv6. (4认同)
  • netifaces不支持py3k,并且需要一个C编译器,它是Windows上的PITA. (3认同)
  • 这个模块必须是标准库的一部分,因为 python 声称“包含电池”的理念 (3认同)

nin*_*cko 48

套接字API方法

请参阅/sf/answers/2026554351/

缺点:

  • 不是跨平台的.
  • 需要更多的后备代码,与互联网上特定地址的存在相关联
  • 如果你在NAT后面,这也行不通
  • 可能会创建一个UDP连接,而不是独立于(通常是ISP)的DNS可用性(请参阅其他答案,例如使用8.8.8.8:Google的(巧合的是DNS)服务器)
  • 确保将目标地址设置为UNREACHABLE,例如规格保证未使用的数字IP地址.请勿使用fakesubdomain.google.com或somefakewebsite.com等域名; 您仍然会在该方(现在或将来)发送垃圾邮件,并在此过程中向您自己的网络框发送垃圾邮件.

反射器方法

(请注意,这不符合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)
Run Code Online (Sandbox Code Playgroud)

或者如果使用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)
Run Code Online (Sandbox Code Playgroud)

好处:

  • 这种方法的一个优点是它是跨平台的
  • 它适用于丑陋的NAT(例如你的家用路由器).

缺点(和解决方法):

  • 需要这个网站,不改变的格式(几乎肯定不会),你的DNS服务器工作.通过在发生故障时查询其他第三方IP地址反射器,可以缓解此问题.
  • 如果你不查询多个反射器(防止被泄露的反射器告诉你你的地址不是这样的话),或者如果你不使用HTTPS(以防止中间人攻击假装),可能的攻击向量成为服务器)

编辑:虽然最初我认为这些方法非常糟糕(除非你使用很多后备,但代码可能在很多年后都无关紧要),它确实提出了"什么是互联网?"的问题.计算机可能有许多指向许多不同网络的接口.有关该主题的更全面描述,请访问google gateways and routes.计算机可以通过内部网关访问内部网络,或者通过例如路由器(通常是这种情况)上的网关访问万维网.OP询问的本地IP地址仅针对单个链路层进行了明确定义,因此您必须指定("它是网卡,还是以太网电缆,我们正在谈论它?") .提出的问题可能有多个非独特的答案.然而,万维网上的全球IP地址可能是明确定义的(在没有大规模网络碎片的情况下):可能是通过可以访问TLD的网关的返回路径.

  • 作为套接字API版本中的替代方法,将s.connect(('INSERT SOME TARGET WEBSITE.com',0))替换为s.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1); s.connect((' broadcast&gt;',0)),以避免DNS查找。(我猜如果有防火墙,广播可能会出问题) (2认同)

Col*_*son 44

如果计算机具有到Internet的路由,则即使未正确设置/ etc/hosts ,也始终可以获取首选本地IP地址.

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]
Run Code Online (Sandbox Code Playgroud)


tMC*_*tMC 38

在Linux上:

>>> import socket, struct, fcntl
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> sockfd = sock.fileno()
>>> SIOCGIFADDR = 0x8915
>>>
>>> def get_ip(iface = 'eth0'):
...     ifreq = struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)
...     try:
...         res = fcntl.ioctl(sockfd, SIOCGIFADDR, ifreq)
...     except:
...         return None
...     ip = struct.unpack('16sH2x4s8x', res)[2]
...     return socket.inet_ntoa(ip)
... 
>>> get_ip('eth0')
'10.80.40.234'
>>> 
Run Code Online (Sandbox Code Playgroud)

  • 可以在Python3上进行一次修改:`struct.pack('16sH14s',iface,socket.AF_INET,'\ x00'*14)`应该替换为`struct.pack('16sH14s',iface.encode('utf-) 8'),socket.AF_INET,b'\ x00'*14)` (2认同)
  • @ChristianFischer `ioctl` 是一个遗留接口,我认为它不支持 IPv6,而且可能永远不会支持。我认为“正确”的方式是通过 Netlink,这在 Python 中不是很简单。我认为 libc 应该有函数 `getifaddrs` 可以通过 pythons `ctypes` 模块访问它可以工作 - http://man7.org/linux/man-pages/man3/getifaddrs.3.html (2认同)

sme*_*lin 27

我正在使用以下模块:

#!/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
Run Code Online (Sandbox Code Playgroud)

使用windows和linux进行测试(并且不需要额外的模块),用于基于单个IPv4的LAN中的系统.

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

  • 这与新的可预测 Linux 接口名称不兼容,例如 `enp0s25`。有关更多信息,请参阅 https://wiki.archlinux.org/index.php/Network_Configuration#Device_names (2认同)
  • 我使用python 3.4并且'struct.pack(...)'部分需要更改为'struct.pack('256s',bytes(ifname [:15],'utf-8'))'.请参阅此问题:http://stackoverflow.com/q/27391167/76010 (2认同)

shi*_*ino 24

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

import commands
commands.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:]
Run Code Online (Sandbox Code Playgroud)

这不起作用.

  • 自2.6以来已弃用.使用[subprocess module](http://docs.python.org/2/library/subprocess.html)运行命令. (7认同)
  • 而ifconfig也被弃用了.使用iproute2. (5认同)

Dzi*_*inX 20

如果您不想使用外部程序包并且不想依赖外部Internet服务器,这可能会有所帮助.这是我在Google代码搜索中找到并修改为返回所需信息的代码示例:

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
Run Code Online (Sandbox Code Playgroud)

用法:

>>> for addr in getIPAddresses():
>>>    print addr
192.168.0.100
10.5.9.207
Run Code Online (Sandbox Code Playgroud)

由于它依赖windll,这只适用于Windows.

  • +1此技术至少尝试返回计算机上的所有地址. (14认同)

www*_*Com 18

关于Debian(测试),我怀疑大多数Linux的..

import commands

RetMyIP = commands.getoutput("hostname -I")
Run Code Online (Sandbox Code Playgroud)

在MS Windows上(已测试)

import socket

socket.gethostbyname(socket.gethostname())
Run Code Online (Sandbox Code Playgroud)

  • 不适用于 macOS:`主机名:非法选项 -- I\nusage:主机名 [-fs] [主机名]` (2认同)

小智 18

我认为这个版本尚未发布.我在Ubuntu 12.04上使用python 2.7进行了测试.

在以下网址找到此解决方案:http://code.activestate.com/recipes/439094-get-the-ip-address-associated-with-a-network-inter/

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])
Run Code Online (Sandbox Code Playgroud)

结果示例:

>>> get_ip_address('eth0')
'38.113.228.130'
Run Code Online (Sandbox Code Playgroud)

  • 适用于Python3,Ubuntu 18.04; 该字符串必须是字节:>>> socket.inet_ntoa(fcntl.ioctl(s.fileno(),0x8915,struct.pack('256s','enp0s31f6'[:15] .encode('utf-8') ))[20:24])'192.168.1.1' (2认同)

dlm*_*dlm 11

ninjagecko答案的变化.这应该适用于允许UDP广播的任何LAN,并且不需要访问LAN或Internet上的地址.

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())
Run Code Online (Sandbox Code Playgroud)

  • 不适用于 Mac OS 11.1。看到这个错误:socket.error: [Errno 49] 无法分配请求的地址 (2认同)

Jas*_*ker 8

我担心除了连接到另一台计算机并让它向您发送您的IP地址之外,没有任何好的平台独立方法可以做到这一点.例如: findmyipaddress.请注意,如果您需要NAT后面的IP地址,除非您连接的计算机也在NAT后面,否则这将不起作用.

这是一个适用于Linux的解决方案: 获取与网络接口关联的IP地址.


小智 8

通过命令行工具生成"干净"输出的一种简单方法:

import commands
ips = commands.getoutput("/sbin/ifconfig | grep -i \"inet\" | grep -iv \"inet6\" | " +
                         "awk {'print $2'} | sed -ne 's/addr\:/ /p'")
print ips
Run Code Online (Sandbox Code Playgroud)

它将显示系统上的所有IPv4地址.


Kas*_*sen 8

对于Linux,可以只使用check_output了的hostname -I,像这样的系统命令:

from subprocess import check_output
check_output(['hostname', '-I'])
Run Code Online (Sandbox Code Playgroud)


gav*_*etz 7

仅供参考我可以验证方法:

import socket
addr = socket.gethostbyname(socket.gethostname())
Run Code Online (Sandbox Code Playgroud)

适用于OS X(10.6,10.5),Windows XP和管理良好的RHEL部门服务器.它在一个非常小的CentOS VM上无法工作,我只是做了一些内核攻击.因此,对于该实例,您只需检查127.0.0.1地址,在这种情况下执行以下操作:

if addr == "127.0.0.1":
     import commands
     output = commands.getoutput("/sbin/ifconfig")
     addr = parseaddress(output)
Run Code Online (Sandbox Code Playgroud)

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


Eli*_*ins 7

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

# imports
import errno
import socket

# 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:
        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
Run Code Online (Sandbox Code Playgroud)


Nak*_*lon 6

import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]
Run Code Online (Sandbox Code Playgroud)

  • 嗯...在具有两个 NIC 的服务器上,这提供了 *一个 * 分配的 IP 地址,但重复了 3 次。在我的笔记本电脑上,它给出了“127.0.1.1”(重复了三遍......)... (2认同)

fcc*_*lho 5

这适用于大多数Linux机箱:

import socket, subprocess, re
def get_ipv4_address():
    """
    Returns IP address(es) of current machine.
    :return:
    """
    p = subprocess.Popen(["ifconfig"], stdout=subprocess.PIPE)
    ifc_resp = p.communicate()
    patt = re.compile(r'inet\s*\w*\S*:\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
    resp = patt.findall(ifc_resp[0])
    print resp

get_ipv4_address()
Run Code Online (Sandbox Code Playgroud)


Wol*_*age 5

这个答案是我个人尝试解决获取局域网IP的问题,因为socket.gethostbyname(socket.gethostname())还返回了127.0.0.1.此方法不需要Internet仅LAN连接.代码适用于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())
Run Code Online (Sandbox Code Playgroud)


hmo*_*rad 5

如果您正在寻找与本地主机 IP 地址不同的 IPV4 地址127.0.0.1,这里有一段简洁的 Python 代码:

import subprocess
address = subprocess.check_output(['hostname', '-s', '-I'])
address = address.decode('utf-8') 
address=address[:-1]
Run Code Online (Sandbox Code Playgroud)

也可以写成一行:

address = subprocess.check_output(['hostname', '-s', '-I']).decode('utf-8')[:-1]
Run Code Online (Sandbox Code Playgroud)

即使您localhost输入/etc/hostname,代码仍会提供您的本地 IP 地址。