如何在Python中获取eth0的IP地址?

Mem*_*r-X 62 python unix networking nic

当Unix上的Python脚本发生错误时,会发送一封电子邮件.

如果IP地址是192.168.100.37(测试服务器),我被要求将{Testing Environment}添加到电子邮件的主题行.通过这种方式,我们可以拥有一个版本的脚本,以及一种判断电子邮件是否来自测试服务器上的混乱数据的方法.

但是,当我谷歌时,我一直在寻找这段代码:

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

但是,这给了我IP地址127.0.1.1.当我使用时,ifconfig我得到了这个

eth0      Link encap:Ethernet  HWaddr 00:1c:c4:2c:c8:3e
          inet addr:192.168.100.37  Bcast:192.168.100.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:75760697 errors:0 dropped:411180 overruns:0 frame:0
          TX packets:23166399 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:59525958247 (59.5 GB)  TX bytes:10142130096 (10.1 GB)
          Interrupt:19 Memory:f0500000-f0520000

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:25573544 errors:0 dropped:0 overruns:0 frame:0
          TX packets:25573544 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:44531490070 (44.5 GB)  TX bytes:44531490070 (44.5 GB)
Run Code Online (Sandbox Code Playgroud)

首先,我不知道它从哪里得到127.0.1.1,但无论哪种方式都不是我想要的.当我谷歌时,我继续使用相同的语法,Bash脚本或netifaces,我正在尝试使用标准库.

那么如何在Python中获取eth0的IP地址呢?

Mar*_*cny 155

两种方法:

方法#1(使用外部包)

您需要询问绑定到您的eth0接口的IP地址.这可以从netifaces包中获得

import netifaces as ni
ni.ifaddresses('eth0')
ip = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
print ip  # should print "192.168.100.37"
Run Code Online (Sandbox Code Playgroud)

您还可以通过以下方式获取所有可用接口的列表

ni.interfaces()
Run Code Online (Sandbox Code Playgroud)

方法#2(无外部包装)

这是一种在不使用python包的情况下获取IP地址的方法:

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

注意:检测IP地址以确定您正在使用的环境非常糟糕.几乎所有框架都提供了一种非常简单的方法来设置/修改环境变量以指示当前环境.请尝试查看您的文档.它应该像做一样简单

if app.config['ENV'] == 'production':
  #send production email
else:
  #send development email
Run Code Online (Sandbox Code Playgroud)

  • 对于Python 3,ifname [:15]应该是字节(ifname [:15],'utf-8') (15认同)
  • 鉴于它是Python,导入netifaces作为ni是特别合适的......对于一些骑士来说至少.;-) (8认同)
  • 我知道我迟到了,但有人可以解释编辑2的巫术吗?我是套接字库的新手,从未使用过其他两个. (3认同)
  • 为什么ifname [:15]而不仅仅是ifname? (2认同)
  • @AustinA [`ioctl`](http://man7.org/linux/man-pages/man2/ioctl.2.html) 是对不适合常见 `read` 的文件描述符执行操作的常见方法/`写`语义。因为可能会执行[大量不同的操作](http://man7.org/linux/man-pages/man2/ioctl_list.2.html),所以 `ioctl` 需要一个指示操作的代码。这里,“SIOCGIFADDR”的意思是“**s**ocket **ioc**tl **g**et **i**nter**f**ace **addr**ess”。 (2认同)
  • @AustinA `SIOCGIFADDR` 通过 [`struct ifreq` ](http://man7.org/linux/man-pages/man7/netdevice.7.html) 结构接收/返回信息。这个非常简短的代码利用了接口名称在该结构中偏移量为零的事实,并且只是将一个大的填充 blob 传递给内核。然后,它从偏移量 20 处的 struct sockaddr 中读取 32 位地址。这可以写得很清楚,但这样就完成了工作。 (2认同)
  • 方法 2 每次调用都会泄漏一个套接字。您需要在 finally 块中调用 s.close() 。 (2认同)
  • 方法#2给出错误“OSError:[Errno 6]设备未配置”MAC(Darwin内核版本19.6.0:root:xnu-6153.141.1~1/RELEASE_X86_64 x86_64) (2认同)

jer*_*own 102

或者,如果要获取用于连接到网络的任何接口的IP地址而不必知道其名称,可以使用以下命令:

import socket
def get_ip_address():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.connect(("8.8.8.8", 80))
    return s.getsockname()[0]
Run Code Online (Sandbox Code Playgroud)

我知道这与你的问题有点不同,但其他人可能会到这里找到这个更有用的.您没有必要使用8.8.8.8的路由来使用它.它所做的只是打开一个套接字,但不发送任何数据.

  • 很棒的解决方案. (3认同)
  • 是的,可能不会去任何地方,但有些局域网可能不会暴露给它. (2认同)

小智 28

为接口返回带有ip-addresses的字符串的简单方法是:

from subprocess import check_output

ips = check_output(['hostname', '--all-ip-addresses'])
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅主机名.

  • 这是特定于 Linux 网络工具版本的 `hostname`。Mac/BSD 主机名命令不提供此功能。如果您使用的是 Linux 版本,这可能是最简单的方法。 (3认同)

小智 16

如果你只需要在Unix上工作,你可以使用系统调用(参考Stack Overflow问题Parse ifconfig只使用Bash获取我的IP地址):

import os
f = os.popen('ifconfig eth0 | grep "inet\ addr" | cut -d: -f2 | cut -d" " -f1')
your_ip=f.read()
Run Code Online (Sandbox Code Playgroud)

  • 这个是特定的分布.例如,在RHEL上,剪切命令会切断错误的术语.因此,这个版本在*nix发行版中不可移植. (2认同)
  • 这里真的不需要`grep`和`cut`,只需得到输出并解析它.此外,`ip addr`命令可能更受欢迎. (2认同)

Iva*_*eno 15

由于大多数答案用于ifconfig从eth0接口中提取IPv4(不赞成使用),ip addr因此可以使用以下代码:

import os

ipv4 = os.popen('ip addr show eth0 | grep "\<inet\>" | awk \'{ print $2 }\' | awk -F "/" \'{ print $1 }\'').read().strip()
ipv6 = os.popen('ip addr show eth0 | grep "\<inet6\>" | awk \'{ print $2 }\' | awk -F "/" \'{ print $1 }\'').read().strip()
Run Code Online (Sandbox Code Playgroud)

更新:

或者,您可以使用split()而不是grep和awk 将部分解析任务转移到python解释器,如@serg在注释中指出:

import os

ipv4 = os.popen('ip addr show eth0').read().split("inet ")[1].split("/")[0]
ipv6 = os.popen('ip addr show eth0').read().split("inet6 ")[1].split("/")[0]
Run Code Online (Sandbox Code Playgroud)

但在这种情况下,您必须检查每次split()调用返回的数组的边界.

更新2:

使用正则表达式的另一个版本:

import os
import re

ipv4 = re.search(re.compile(r'(?<=inet )(.*)(?=\/)', re.M), os.popen('ip addr show eth0').read()).groups()[0]
ipv6 = re.search(re.compile(r'(?<=inet6 )(.*)(?=\/)', re.M), os.popen('ip addr show eth0').read()).groups()[0]
Run Code Online (Sandbox Code Playgroud)

  • 使用`ip addr`的工作很好但是,实际上没有必要将输出管道输出到grep和awk.Python能够使用split()解析输出 (3认同)

小智 5

这将收集主机上的所有 IP 地址并过滤掉 Loopback/link-local 和IPv6。还可以对其进行编辑以仅允许 IPv6,或同时允许IPv4和 IPv6,以及允许 IP 地址列表中的环回/本地链路。

from socket import getaddrinfo, gethostname
import ipaddress

def get_ip(ip_addr_proto="ipv4", ignore_local_ips=True):
    # By default, this method only returns non-local IPv4 addresses
    # To return IPv6 only, call get_ip('ipv6')
    # To return both IPv4 and IPv6, call get_ip('both')
    # To return local IPs, call get_ip(None, False)
    # Can combine options like so get_ip('both', False)

    af_inet = 2
    if ip_addr_proto == "ipv6":
        af_inet = 30
    elif ip_addr_proto == "both":
        af_inet = 0

    system_ip_list = getaddrinfo(gethostname(), None, af_inet, 1, 0)
    ip_list = []

    for ip in system_ip_list:
        ip = ip[4][0]

        try:
            ipaddress.ip_address(str(ip))
            ip_address_valid = True
        except ValueError:
            ip_address_valid = False
        else:
            if ipaddress.ip_address(ip).is_loopback and ignore_local_ips or ipaddress.ip_address(ip).is_link_local and ignore_local_ips:
                pass
            elif ip_address_valid:
                ip_list.append(ip)

    return ip_list

print(f"Your IP address is: {get_ip()}")
Run Code Online (Sandbox Code Playgroud)

退货

您的IP地址是:['192.168.1.118']

如果我运行 get_ip('both', False),它会返回

您的 IP 地址是:['::1', 'fe80::1', '127.0.0.1', '192.168.1.118', 'fe80::cb9:d2dd:a505:423a']