Поиск локальных IP-адресов с использованием Python's stdlib - PullRequest
480 голосов
/ 03 октября 2008

Как найти локальные IP-адреса (например, 192.168.x.x или 10.0.x.x) на платформе Python независимо и с использованием только стандартной библиотеки?

Ответы [ 43 ]

19 голосов
/ 03 октября 2008

Если вы не хотите использовать внешние пакеты и не хотите полагаться на внешние интернет-серверы, это может помочь. Это пример кода, который я нашел в Google Code Search и изменил для получения необходимой информации:

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

Поскольку он опирается на windll, это будет работать только в Windows.

17 голосов
/ 06 января 2015

Версия, которую я не верю, была опубликована. Я тестировал с python 2.7 на Ubuntu 12.04.

Нашел это решение по адресу: 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])

Пример результата:

>>> get_ip_address('eth0')
'38.113.228.130'
16 голосов
/ 04 июля 2014

На Debian (протестировано) и я подозреваю, что большинство Linux ..

import commands

RetMyIP = commands.getoutput("hostname -I")

В MS Windows (проверено)

import socket

socket.gethostbyname(socket.gethostname())
11 голосов
/ 23 мая 2014

Вариация ответа ниндзягецко. Это должно работать в любой локальной сети, где разрешена широковещательная рассылка UDP и не требуется доступ к адресу в локальной сети или в Интернете.

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())
8 голосов
/ 13 июня 2011

Один простой способ произвести «чистый» вывод через утилиты командной строки:

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

Он покажет все IPv4-адреса в системе.

8 голосов
/ 03 октября 2008

Боюсь, не существует хороших независимых от платформы способов сделать это, кроме как подключиться к другому компьютеру и заставить его отправить вам ваш IP-адрес. Например: findmyipaddress . Обратите внимание, что это не будет работать, если вам нужен IP-адрес, который находится за NAT, если только компьютер, к которому вы подключаетесь, не находится за NAT.

Вот одно решение, которое работает в Linux: получает IP-адрес, связанный с сетевым интерфейсом .

7 голосов
/ 20 декабря 2013

Это вариант ответа UnkwnTech - он предоставляет функцию get_local_addr(), которая возвращает IP-адрес первичной локальной сети хоста. Я публикую его, потому что это добавляет ряд вещей: поддержку ipv6, обработку ошибок, игнорирование адресов localhost / linklocal и использование адреса TESTNET (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
7 голосов
/ 30 декабря 2009

К вашему сведению, я могу убедиться, что метод:

import socket
addr = socket.gethostbyname(socket.gethostname())

Работает в OS X (10.6,10.5), Windows XP и на хорошо управляемом сервере RHEL отдела. Он не работал на очень минимальной виртуальной машине CentOS, на которой я просто взломал ядро. Поэтому для этого экземпляра вы можете просто проверить адрес 127.0.0.1 и в этом случае сделать следующее:

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

А затем проанализировать IP-адрес из вывода. Следует отметить, что ifconfig не входит в PATH обычного пользователя по умолчанию, и поэтому я даю полный путь в команде. Надеюсь, это поможет.

6 голосов
/ 27 апреля 2012

Это будет работать на большинстве 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()
6 голосов
/ 07 мая 2013
import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]
...