Question

J'ai plusieurs cartes d'interface réseau sur mon ordinateur, chacune avec sa propre adresse IP.

Lorsque j'utilise gethostbyname (gethostname ()) à partir du module socket de Python (intégré), il n'en retournera qu'un. Comment puis-je obtenir les autres?

Était-ce utile?

La solution

Utilisez le module netifaces . La mise en réseau étant complexe, utiliser des netifaces peut être un peu délicat, mais voici comment faire ce que vous voulez:

>>> 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

Cela peut être rendu un peu plus lisible comme ceci:

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

Si vous voulez des adresses IPv6, utilisez AF_INET6 au lieu de AF_INET . Si vous vous demandez pourquoi netifaces utilise des listes et des dictionnaires partout, c'est parce qu'un même ordinateur peut avoir plusieurs cartes réseau et que chaque carte peut avoir plusieurs adresses et que chaque adresse possède son propre ensemble d'options. .

Autres conseils

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

Toutes les adresses sur une ligne à l'aide du module netifaces :

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

Juste pour être complet, une autre option consisterait à utiliser 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))

Explication

La fonction dont vous avez besoin est net_if_addrs . I.e.:

import psutil
psutil.net_if_addrs()

Ce qui donne quelque chose comme ça (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)]}

Remarque : étant donné que vous pouvez associer plusieurs adresses de la même famille à chaque interface, les valeurs dict sont des listes.

Chaque snic est un namedtuple qui comprend 5 champs:

  • famille : la famille d'adresses, soit AF_INET, AF_INET6 ou psutil.AF_LINK, qui fait référence à une adresse MAC.
  • adresse : adresse principale de la carte réseau (toujours définie).
  • masque de réseau : adresse du masque de réseau (peut être Aucun).
  • broadcast : l'adresse de diffusion (peut être aucun).
  • ptp : signifie & # 8220; point à point & # 8221 ;; il s’agit de l’adresse de destination sur une interface point à point (généralement un VPN). broadcast et ptp s’excluent mutuellement (il peut s’agir de Aucun).

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

socket.if_nameindex ()

Renvoie une liste d'informations sur l'interface réseau (index int, chaîne de nom). OSError si l'appel système échoue.

Disponibilité: Unix.

Nouveauté de la version 3.3.

a créé ce code exécutable sous 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() )

imprimera quelque chose comme:

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

C’est uniquement Linux, mais il existe une recette très simple ici http://code.activestate.com / recettes / 439094 /

Il utilise probablement un code similaire au paquet netifaces mentionné dans une autre réponse (mais en cours). version liée ici)

socket.getaddrinfo () ne renvoie pas l'adresse IP liée au périphérique. Si votre fichier hosts contient une ligne avec "127.0.1.1 yourhost.example.com yourhost", qui est une configuration courante, getaddrinfo ne renverra que 127.0.1.1.

Voici une routine pour trouver toutes les interfaces IPv4 et IPv6. Comme l'a déjà souligné un autre poster, socket.gethostbyname_ex () ne fonctionne pas pour IPv6 et la documentation Python recommande une utilisation socket.getaddressinfo () à la place.

Cette routine ajoute l'interface de rappel IPv4 (127.0.0.1). S'il existe des interfaces IPv6, elle ajoute également l'interface de rappel IPv6 (:: 1). Socket.getaddrinfo () me donnera l’un ou les deux, mais seulement si je n’ai pas d’autres interfaces disponibles.

Pour répondre à mes besoins, je souhaitais ouvrir un socket UDP sur un port spécifié de chacune de mes interfaces disponibles. C’est pourquoi le code contient "port". et socket.SOCK_DGRAM dedans. Il est prudent de changer ceux-ci, par exemple si vous n'avez pas de port en tête.

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]

Cet extrait donnera une liste de toutes les adresses IPV4 disponibles dans le système.

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]

Vous devez obtenir directement toutes les adresses IP configurées IP, par exemple. en exécutant ifconfig et en analysant sa sortie (il est également possible de faire ce que ifconfig fait directement en Python , voyez comment cela se fait en C ). Si vous voulez des noms d’hôtes, utilisez gethostbyaddr.

Vous pouvez le faire assez facilement comme ceci:

import netifaces

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

Pour plus d'informations, vous pouvez consulter la documentation de netifaces .

Je pense que la réponse de @Harley Holcombe est réalisable, mais si vous avez des cartes réseau virtuelles sans adresse IP, cela entraînera une erreur. c'est donc je modifié:

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

cela ne fera que renvoyer votre lan ipv4

Comme ce fil l'indique, il existe de nombreuses façons d'obtenir le même résultat. Je suggère d'utiliser le filtre de la famille intégrée dans getaddrinfo () et d'analyser le tuple standardisé comme suit :

from socket import getaddrinfo, AF_INET, gethostname

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

Exemple de sortie:

192.168.55.1
192.168.170.234
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top