我如何确定我所有的IP地址时,我有多个网卡?

问题描述 投票:34回答:12

我有我的计算机上有多个网络接口卡,每个都有自己的IP地址。

当我使用gethostbyname(gethostname())从Python的(内置)socket模块,它只会返回他们中的一个。如何获得其他人呢?

python sockets ip-address
12个回答
45
投票

使用netifaces模块。由于网络是复杂的,使用netifaces可以是一个有点棘手,但这里是如何做到你想要什么:

>>> import netifaces
>>> netifaces.interfaces()
['lo', 'eth0']
>>> netifaces.ifaddresses('eth0')
{17: [{'broadcast': 'ff:ff:ff:ff:ff:ff', 'addr': '00:11:2f:32:63:45'}], 2: [{'broadcast': '10.0.0.255', 'netmask': '255.255.255.0', 'addr': '10.0.0.2'}], 10: [{'netmask': 'ffff:ffff:ffff:ffff::', 'addr': 'fe80::211:2fff:fe32:6345%eth0'}]}
>>> for interface in netifaces.interfaces():
...   print netifaces.ifaddresses(interface)[netifaces.AF_INET]
...
[{'peer': '127.0.0.1', 'netmask': '255.0.0.0', 'addr': '127.0.0.1'}]
[{'broadcast': '10.0.0.255', 'netmask': '255.255.255.0', 'addr': '10.0.0.2'}]
>>> for interface in netifaces.interfaces():
...   for link in netifaces.ifaddresses(interface)[netifaces.AF_INET]:
...     print link['addr']
...
127.0.0.1
10.0.0.2

这可以做多一点可读性是这样的:

from netifaces import interfaces, ifaddresses, AF_INET

def ip4_addresses():
    ip_list = []
    for interface in interfaces():
        for link in ifaddresses(interface)[AF_INET]:
            ip_list.append(link['addr'])
    return ip_list

如果你想IPv6地址,使用AF_INET6代替AF_INET的。如果你想知道为什么netifaces使用列表和字典所有的地方,这是因为一台计算机可以有多个网卡,每个NIC可以有多个地址,每个地址都有其自己的一套方案。


0
投票

你可以这样做很容易像这样:

import netifaces

for interface in netifaces.interfaces():
    print netifaces.ifaddresses(interface)

欲了解更多信息,你可以查查netifaces documentation


0
投票

我认为@Harley霍尔科姆的回答是可行的,但如果你有一些虚拟网卡没有IP就会报错。因此,这是我修改:

def get_lan_ip():
for interface in interfaces():
    try:
        for link in ifaddresses(interface)[AF_INET]:
            if str(link['addr']).startswith("172."):
                return str(link['addr'])
    except:
        pass

这只会回到你的局域网的IPv4


0
投票

由于这个线程表明,有很多的方式来达到同样的效果,我建议的方法是利用在qazxsw POI集结家庭过滤器和解析标准化的元组,如下所示:

getaddrinfo()

示例输出:

from socket import getaddrinfo, AF_INET, gethostname

for ip in getaddrinfo(host=gethostname(), port=None, family=AF_INET):   
    print(ip[4][0])

12
投票
import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]

9
投票

netifaces模块的帮助下一条线的所有地址:

[netifaces.ifaddresses(iface)[netifaces.AF_INET][0]['addr'] for iface in netifaces.interfaces() if netifaces.AF_INET in netifaces.ifaddresses(iface)]

8
投票

只是为了完整性,另一种选择是使用psutil

tldr;

import socket
import psutil

def get_ip_addresses(family):
    for interface, snics in psutil.net_if_addrs().items():
        for snic in snics:
            if snic.family == family:
                yield (interface, snic.address)

ipv4s = list(get_ip_addresses(socket.AF_INET))
ipv6s = list(get_ip_addresses(socket.AF_INET6))

说明

你需要的功能是net_if_addrs。即:

import psutil
psutil.net_if_addrs()

这导致了这样的事情(Python 3中):

{'br-ae4880aa80cf': [snic(family=<AddressFamily.AF_INET: 2>, address='172.18.0.1', netmask='255.255.0.0', broadcast='172.18.0.1', ptp=None),
                     snic(family=<AddressFamily.AF_PACKET: 17>, address='02:42:e5:ae:39:94', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
 'docker0': [snic(family=<AddressFamily.AF_INET: 2>, address='172.17.0.1', netmask='255.255.0.0', broadcast='172.17.0.1', ptp=None),
             snic(family=<AddressFamily.AF_PACKET: 17>, address='02:42:38:d2:4d:77', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
 'eno1': [snic(family=<AddressFamily.AF_PACKET: 17>, address='54:be:f7:0b:cf:a9', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
 'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast=None, ptp=None),
        snic(family=<AddressFamily.AF_PACKET: 17>, address='00:00:00:00:00:00', netmask=None, broadcast=None, ptp=None)],
 'wlp2s0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.4', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
            snic(family=<AddressFamily.AF_PACKET: 17>, address='00:21:27:ee:d6:03', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}

(Python的2):

{'br-ae4880aa80cf': [snic(family=2, address='172.18.0.1', netmask='255.255.0.0', broadcast='172.18.0.1', ptp=None),
                     snic(family=17, address='02:42:e5:ae:39:94', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
 'docker0': [snic(family=2, address='172.17.0.1', netmask='255.255.0.0', broadcast='172.17.0.1', ptp=None),
             snic(family=17, address='02:42:38:d2:4d:77', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
 'eno1': [snic(family=17, address='54:be:f7:0b:cf:a9', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
 'lo': [snic(family=2, address='127.0.0.1', netmask='255.0.0.0', broadcast=None, ptp=None),
        snic(family=17, address='00:00:00:00:00:00', netmask=None, broadcast=None, ptp=None)],
 'wlp2s0': [snic(family=2, address='192.168.1.4', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
            snic(family=17, address='00:21:27:ee:d6:03', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}

注意:因为你可以有每个接口相关联的同一个家庭的多个地址,该字典的值列表。

每个snicnamedtuple其包括5个字段:

  • family:地址族,无论是AF_INET,AF_INET6或psutil.AF_LINK,其指的是MAC地址。
  • address:主NIC地址(总是被设置)。
  • netmask:网络掩码地址(可以是无)。
  • broadcast:广播地址(可以是无)。
  • ptp:代表“点对点”;这是一个点对点接口(通常是VPN)的目标地址。广播和PTP是互斥的(可以是无)。

3
投票

https://docs.python.org/3.4/library/socket.html#socket.if_nameindex

socket.if_nameindex()

返回的网络接口信息(索引INT,名称字符串)元组的列表。 OSERROR如果系统调用失败。

可用性:Unix的。

新的3.3版。


使这个代码,可运行于Python的3.4,在UNIX / Linux

#!/env/python3.4
import socket
import fcntl
import struct

def active_nic_addresses():
    """
    Return a list of IPv4 addresses that are active on the computer.
    """

    addresses = [ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1]

    return addresses

def get_ip_address( NICname ):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
        s.fileno(),
        0x8915,  # SIOCGIFADDR
        struct.pack('256s', NICname[:15].encode("UTF-8"))
    )[20:24])


def nic_info():
    """
    Return a list with tuples containing NIC and IPv4
    """
    nic = []

    for ix in socket.if_nameindex():
        name = ix[1]
        ip = get_ip_address( name )

        nic.append( (name, ip) )

    return nic

if __name__ == "__main__":

    print( active_nic_addresses() )
    print( nic_info() )

将打印类似:

['192.168.0.2']
[('lo', '127.0.0.1'), ('enp3s0', '192.168.0.2')]

1
投票

这只是公司的Linux,但这里有一个非常简单的食谱http://code.activestate.com/recipes/439094/

它可能使用类似的代码在另一个答复中提到的netifaces package(但现行版本的链接)

该socket.getaddrinfo()并不真正用于设备返回绑定的IP地址。如果您的主机文件包含“127.0.1.1 yourhost.example.com yourhost”一条线,这是一种常见的配置,的getaddrinfo只会返回127.0.1.1。


1
投票

这里是查找所有的IPv4和IPv6接口程序。作为以前的海报指出,socket.gethostbyname_ex()不能用于IPv6的工作,Python文档建议一个使用socket.getaddressinfo()代替。

这个程序增加了回调的IPv4接口(127.0.0.1),如果有任何IPv6接口,然后它也增加了回调的IPv6接口(:: 1)。在我的机器,socket.getaddrinfo()会给我其中的一个或两个,但只有当我没有其他接口可用。

对于我的需求,我想尝试在我的每一个可用接口打开一个UDP套接字绑定到特定端口,这就是为什么代码中有“口”和socket.SOCK_DGRAM在里面。它是安全的,改变这些,例如如果你没有考虑到的端口。

addrinfo_ipv4 = socket.getaddrinfo(hostname,port,socket.AF_INET,socket.SOCK_DGRAM)
addrinfo_ipv6 = []
try:
    addrinfo_ipv6 = socket.getaddrinfo(hostname,port,socket.AF_INET6,socket.SOCK_DGRAM)
except socket.gaierror:
    pass
addrinfo = [(f,t,a) for f,t,p,cn,a in addrinfo_ipv4+addrinfo_ipv6]
addrinfo_local = [(socket.AF_INET,socket.SOCK_DGRAM,('127.0.0.1',port))]
if addrinfo_ipv6: 
    addrinfo_local.append( (socket.AF_INET6,socket.SOCK_DGRAM,('::1',port)) )
[addrinfo.append(ai) for ai in addrinfo_local if ai not in addrinfo]

1
投票

这段代码会给系统中的所有可用的IPv4地址的列表。

import itertools
from netifaces import interfaces, ifaddresses, AF_INET

links = filter(None, (ifaddresses(x).get(AF_INET) for x in interfaces()))
links = itertools.chain(*links)
ip_addresses = [x['addr'] for x in links]

0
投票

您应该直接获得所有IP配置的IP地址,例如通过运行ifconfig和分析其输出(它也可以做什么ifconfig does directly in Pythonsee how it is done in C)。如果你想主机名,使用gethostbyaddr。

© www.soinside.com 2019 - 2024. All rights reserved.