Как получить собственный локальный IP-адрес с помощью scapy? [Дубликат]

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

435
задан anatoly techtonik 15 December 2013 в 13:19
поделиться

30 ответов

import socket
socket.gethostbyname(socket.gethostname())

Это не будет работать всегда (возвращает 127.0.0.1 на машинах, имеющих имя хоста в /etc/hosts как 127.0.0.1), палиатив будет тем, что показывает gimel, вместо этого используйте socket.getfqdn(). Конечно, ваша машина нуждается в разрешимом имени хоста.

339
ответ дан alexandreferris 22 August 2018 в 08:10
поделиться
  • 1
    Следует отметить, что это не независимое от платформы решение. Многие Linuxes вернут 127.0.0.1 в качестве вашего IP-адреса, используя этот метод. – Jason Baker 3 October 2008 в 13:07
  • 2
    Вариант: socket.gethostbyname (socket.getfqdn ()) – gimel 3 October 2008 в 13:08
  • 3
    Кажется, он возвращает только один IP-адрес. Что делать, если машина имеет несколько адресов? – Jason R. Coombs 23 October 2009 в 15:39
  • 4
    По Ubuntu это возвращает 127.0.1.1 по какой-то причине. – slikts 20 March 2012 в 07:52
  • 5
    @UnkwnTech, пожалуйста, не принимайте ответ, это явно ненадежно. – Federico 7 January 2015 в 13:41
  • 6
    – Barmaley 15 May 2015 в 20:36
130
ответ дан Alexander 22 August 2018 в 08:10
поделиться

Примечание. Это не использует стандартную библиотеку, но довольно просто.

$ pip install pif

from pif import get_public_ip
get_public_ip()
2
ответ дан Artur Barseghyan 22 August 2018 в 08:10
поделиться
  • 1
    вопросы заключались в поиске IP-адреса с использованием stdlib – Chirila Alexandru 3 September 2013 в 14:09

Небольшое уточнение версии команд, использующей команду IP, и возвращает адреса IPv4 и IPv6:

import commands,re,socket

#A generator that returns stripped lines of output from "ip address show"
iplines=(line.strip() for line in commands.getoutput("ip address show").split('\n'))

#Turn that into a list of IPv4 and IPv6 address/mask strings
addresses1=reduce(lambda a,v:a+v,(re.findall(r"inet ([\d.]+/\d+)",line)+re.findall(r"inet6 ([\:\da-f]+/\d+)",line) for line in iplines))
#addresses1 now looks like ['127.0.0.1/8', '::1/128', '10.160.114.60/23', 'fe80::1031:3fff:fe00:6dce/64']

#Get a list of IPv4 addresses as (IPstring,subnetsize) tuples
ipv4s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if '.' in addr)]
#ipv4s now looks like [('127.0.0.1', 8), ('10.160.114.60', 23)]

#Get IPv6 addresses
ipv6s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if ':' in addr)]
4
ответ дан Ben Last 22 August 2018 в 08:10
поделиться

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

import commands

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

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

import socket

socket.gethostbyname(socket.gethostname())
14
ответ дан Bryan Chen 22 August 2018 в 08:10
поделиться

Вы можете использовать модуль netifaces . Просто введите:

pip install netifaces

в командной оболочке и он установит себя по умолчанию для установки на 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))

На моем компьютере он напечатан:

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

Автор этого модуля утверждает, что он должен работать в Windows, UNIX и Mac OS X.

79
ответ дан ccpizza 22 August 2018 в 08:10
поделиться
  • 1
    Как указано в вопросе, я хочу что-то от установки по умолчанию, так как никаких дополнительных установок не требуется. – UnkwnTech 3 October 2008 в 13:52
  • 2
    Это был бы мой любимый ответ, за исключением того, что netifaces не поддерживает IPv6 в Windows и выглядит невосприимчивым. Кто-нибудь понял, как получить IPv6-адреса в Windows? – Jean-Paul Calderone 28 June 2011 в 13:57
  • 3
    netifaces не поддерживает py3k и требует компилятор C, который является PITA на окнах. – Matt Joiner 5 June 2012 в 07:43
  • 4
    @MattJoiner Ни одна из этих вещей не верна (последняя версия имеет двоичные файлы Windows на PyPI и поддерживает Py3K). – alastair 2 May 2014 в 16:42
  • 5
    @ Jean-PaulCalderone FWIW, последняя версия netifaces поддерживает IPv6 в Windows. – alastair 2 May 2014 в 16:43
40
ответ дан Collin Anderson 22 August 2018 в 08:10
поделиться

Ну, вы можете использовать команду «ip route» в GNU / Linux, чтобы узнать ваш текущий IP-адрес.

Это показывает IP-адрес, предоставляемый интерфейсу сервером DHCP, работающим на маршрутизаторе / модемом. Обычно «192.168.1.1/24» - это IP для локальной сети, где «24» означает диапазон возможных IP-адресов, заданных сервером DHCP в пределах диапазона маски.

Вот пример: обратите внимание, что PyNotify является просто добавление, чтобы получить мою точку зрения и вообще не требуется

#! /usr/bin/env python

import sys , pynotify

if sys.version_info[1] != 7:
   raise RuntimeError('Python 2.7 And Above Only')       

from subprocess import check_output # Available on Python 2.7+ | N/A 

IP = check_output(['ip', 'route'])
Split_Result = IP.split()

# print Split_Result[2] # Remove "#" to enable

pynotify.init("image")
notify = pynotify.Notification("Ip", "Server Running At:" + Split_Result[2] , "/home/User/wireless.png")    
notify.show()    

. Преимущество этого в том, что вам не нужно указывать сетевой интерфейс. Это очень полезно при запуске сервера сокетов

. Вы можете установить PyNotify с помощью easy_install или даже Pip:

easy_install py-notify

или

pip install py-notify

или внутри скрипта python / интерпретатор

from pip import main

main(['install', 'py-notify'])
4
ответ дан DarkXDroid 22 August 2018 в 08:10
поделиться

Вариант ответа ниндзягеко. Это должно работать в любой локальной сети, которая позволяет широковещательную рассылку 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())
6
ответ дан dlm 22 August 2018 в 08:10
поделиться

Если вы не хотите использовать внешние пакеты и не хотите полагаться на внешние интернет-серверы, это может помочь. Это код, который я нашел в 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.

19
ответ дан DzinX 22 August 2018 в 08:10
поделиться
  • 1
    Однолинейное решение выше, как правило, работает на окнах. Это проблема Linux, которая является проблемой. – ricree 18 June 2009 в 01:19
  • 2
    +1 Этот метод по крайней мере пытается вернуть все адреса на машине. – Jason R. Coombs 23 October 2009 в 15:42
  • 3
    Этот скрипт выходит из строя на моем компьютере после возвращения первого адреса. Ошибка - это объект «AttributeError:« LP_IP_ADDR_STRING »не имеет атрибута« ipAddress »& quot; Я подозреваю, что это имеет какое-то отношение к IPv6-адресу. – Jason R. Coombs 23 October 2009 в 15:43
  • 4
    Оказывается, проблема в том, что для чего угодно, кроме первого IP-адреса, adNode не разыменовывается. Добавьте еще одну строку в пример в цикле while, и она работает для меня: adNode = adNode.contents – Jason R. Coombs 23 October 2009 в 17:09

Это вариант ответа UnkwnTech - он предоставляет функцию get_local_addr(), которая возвращает основной 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
7
ответ дан Eli Collins 22 August 2018 в 08:10
поделиться

Мне пришлось решить проблему «Поясните, является ли IP-адрес локальным или нет», и я сначала подумал о том, чтобы создать список IP-адресов, которые были локальными, а затем сопоставлены с ним. Вот что привело меня к этому вопросу. Тем не менее, я позже понял, что есть более прямой способ сделать это: попробуйте связать на этом IP-адресе и посмотреть, работает ли он.

_local_ip_cache = []
_nonlocal_ip_cache = []
def ip_islocal(ip):
    if ip in _local_ip_cache:
        return True
    if ip in _nonlocal_ip_cache:
        return False
    s = socket.socket()
    try:
        try:
            s.bind((ip, 0))
        except socket.error, e:
            if e.args[0] == errno.EADDRNOTAVAIL:
                _nonlocal_ip_cache.append(ip)
                return False
            else:
                raise
    finally:
        s.close()
    _local_ip_cache.append(ip)
    return True

Я знаю, что это не отвечает на вопрос напрямую, но это должен быть полезен любому, кто пытается решить соответствующий вопрос и кто следит за тем же путем. Преимущество этого кросс-платформенного решения (я думаю).

2
ответ дан Etienne Perot 22 August 2018 в 08:10
поделиться

Это будет работать в большинстве 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
ответ дан fccoelho 22 August 2018 в 08:10
поделиться

FYI Я могу проверить, что метод:

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 пользователя, поэтому я даю полный путь в команде. Надеюсь, это поможет.

7
ответ дан gavaletz 22 August 2018 в 08:10
поделиться

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

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
ответ дан Gilles 22 August 2018 в 08:10
поделиться
  • 1
    Он не будет отображать все IPv4-адреса, потому что ifconfig сообщает только о первичных. Вам нужно использовать & quot; ip & quot; от iproute2, чтобы увидеть все адреса. – Helmut Grohne 9 April 2013 в 14:02
  • 2
    Это чертовски много оболочек для вопроса, требующего стандартную библиотеку ... Кроме того, разбор ifconfig не является переносимым и даже не будет надежно работать на одной машине. – Dominik George 12 September 2017 в 07:42

Этот метод возвращает «первичный» IP-адрес в локальном поле (тот, у которого есть маршрут по умолчанию).

  • НЕ требуется маршрутизируемый сетевой доступ или любое соединение вообще.
  • Работает, даже если все интерфейсы отключены от сети.
  • НЕ нужно или даже пытаться получить в другом месте .
  • Работает с NAT, публичный, частный, внешний и внутренний IP
  • Pure 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

Это возвращает единственный IP-адрес, который является основным (тот, у которого есть маршрут по умолчанию). Если вам нужно, все IP-адреса, привязанные ко всем интерфейсам (включая localhost и т. Д.), См. В этом ответе .

Если вы находитесь за брандмауэром NAT, например, у вашего Wi-Fi-бокса дома, это не покажет ваш общедоступный IP-адрес NAT, а вместо этого ваш частный IP-адрес NAT в локальной сети, который имеет маршрут по умолчанию к вашему локальному маршрутизатору WIFI; получение внешнего IP-адреса вашего Wi-Fi-маршрутизатора потребует либо запускать это на THAT-боксе, либо подключиться к внешней службе, такой как whatismyip.com/whatismyipaddress.com, которая может отражать IP-адрес ... но это полностью отличается от исходного вопроса. :)

Обновлен вызов connect () по предложению Педро в комментариях. (Если вам нужна конкретная заявка на лицензию, это общедоступный домен / бесплатный для любого использования или MIT / CC2-BY-SA для кода / контента для стека переполнения по вашему выбору.)

98
ответ дан Jamieson Becker 22 August 2018 в 08:10
поделиться
  • 1
    Работает в Raspbian с Python 2 и 3! – pierce.jason 23 September 2015 в 17:03
  • 2
    Brilliant. Работает на Win7,8,8,1 + Linux Mint & amp; Arch, включая виртуальные машины. – shermy 3 March 2016 в 01:07
  • 3
    Работает в Windows 10 Pro! Спасибо, Джеймисон Беккер! – varantes 12 April 2017 в 14:02
  • 4
    По какой-то причине это не работает в 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 – Pedro Scarapicchia Junior 15 April 2017 в 06:36
  • 5
    @PedroScarapicchiaJunior удивительное предложение, обновленный ответ. Благодаря!! – Jamieson Becker 17 April 2017 в 22:24

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

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

7
ответ дан Jason Baker 22 August 2018 в 08:10
поделиться
13
ответ дан linusg 22 August 2018 в 08:10
поделиться

Я использую это на своих машинах ubuntu:

import commands
commands.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:]

Это не работает.

25
ответ дан martinarroyo 22 August 2018 в 08:10
поделиться
  • 1
    Ницца и просто. Работает на Amazon's Linux AMI, но только если я root. В противном случае я получаю сообщение об ошибке: 'sh: ifconfig: command not found' – Igor Ganapolsky 10 November 2010 в 17:52
  • 2
    Поэтому вы должны использовать & quot; / sbin / ifconfig & quot; как сказал гавалец. Он также работает на Red Hat 4.1.2-48. – Igor Ganapolsky 10 November 2010 в 18:05
  • 3
    Устаревший с 2.6. Используйте модуль subprocess для запуска команд. – Colin Dunklau 18 March 2013 в 23:06
  • 4
    И ifconfig также устарел. Используйте iproute2. – Helmut Grohne 9 April 2013 в 14:04
  • 5
    Получить все ips: import sh; [ip.split () [1] [5:] для ip в фильтре (lambda x: 'inet addr' в x, sh.ifconfig (). split ("\n"))] – Gabriel Littman 28 February 2014 в 00:43
import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]
6
ответ дан Nakilon 22 August 2018 в 08:10
поделиться
  • 1
    Хм ... на сервере с двумя сетевыми адаптерами это дает один назначенных IP-адресов, но повторяется три раза. На моем ноутбуке он дает «127.0.1.1» (повторяется три раза ...) ... – bryn 20 November 2013 в 15:30
  • 2
    Дает мне ['fe80::34e8:fe19:1459:2cde%22','fe80::d528:99fb:d572:e289%12', '192.168.56.1', '192.168.1.2'] на рабочем столе Windows. – Nakilon 19 July 2014 в 04:48

Метод Socket API

см. https://stackoverflow.com/a/28950776/711085

Недостатки:

  • Не кросс-платформенный.
  • Требуется дополнительный резервный код, привязанный к существованию определенных адресов в Интернете
  • Это также не сработает, если вы за поддержкой NAT
  • Вероятно, создается соединение UDP, не зависящее от доступности DNS (как правило, ISP) (см. другие ответы для таких идей, как использование 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)

или использовать 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)

Преимущества:

  • Одним из достоинств этого метода является кросс-платформенный
  • Он работает из-за уродливых NAT (например, вашего домашнего маршрутизатора).

Недостатки (и обходные пути):

  • Требуется, чтобы этот сайт был вверх, формат не менялся (почти наверняка не будет), а ваши DNS-серверы будут работать. Можно устранить эту проблему, также обратившись к другим сторонним отражателям IP-адресов в случае сбоя.
  • Возможный вектор атаки, если вы не запрашиваете несколько отражателей (чтобы предотвратить скомпрометированный отражатель от вас, что ваш адрес это что-то не так), или если вы не используете HTTPS (чтобы предотвратить атаку «человек в середине», претендующий на роль сервера)

изменить : Хотя изначально я думал, что эти методы были очень плохими (если вы не используете много резервных копий, код может быть неактуальным через много лет), он задает вопрос «что такое интернет?». Компьютер может иметь множество интерфейсов, указывающих на множество разных сетей. Для более подробного описания темы google для gateways and routes. Компьютер может иметь доступ к внутренней сети через внутренний шлюз или получить доступ к всемирной сети через шлюз, например, для маршрутизатора (как правило, для случая). Локальный IP-адрес, о котором спрашивает OP, только четко определен в отношении одного уровня связи, поэтому вы должны указать, что («это сетевая карта или кабель Ethernet, о котором мы говорим?») , На этот вопрос может быть несколько неповторимых ответов. Однако глобальный IP-адрес во всемирной сети, вероятно, хорошо определен (в отсутствие массивной фрагментации сети): возможно, путь возврата через шлюз, который может получить доступ к TLD.

48
ответ дан ninjagecko 22 August 2018 в 08:10
поделиться
  • 1
    Это вернет адрес вашей локальной сети, если вы находитесь за NAT. Если вы подключаетесь к Интернету, вы можете подключиться к веб-службе, которая возвращает один из ваших общедоступных IP-адресов. – phihag 23 June 2011 в 12:10
  • 2
    @phihag: вы должны психически, потому что я просто редактировал свой ответ, чтобы сказать это! – ninjagecko 23 June 2011 в 12:11
  • 3
    Он не создает TCP-соединение, поскольку создает соединение UDP. – Anuj Gupta 26 March 2013 в 18:41
  • 4
    @AnujGupta: ах, конечно, спасибо, спасибо ... – ninjagecko 9 April 2013 в 16:52
  • 5
    В качестве альтернативы в версии API сокета замените s.connect ((«INSERT SOME TARGET WEBSITE.com», 0)) с помощью s.setsockopt (socket.SOL_SOCKET, socket.SO_BROADCAST, 1); s.connect (('& lt; , broadcast & gt; ', 0)), чтобы избежать поиска DNS. (Я думаю, может быть проблема с трансляцией, если есть брандмауэр) – dlm 12 August 2013 в 04:55
import socket
socket.gethostbyname(socket.getfqdn())
2
ответ дан Oink 22 August 2018 в 08:10
поделиться
  • 1
    Вместо того, чтобы публиковать блок кода, пожалуйста, объясните , почему этот код решает поставленную проблему. Без объяснений это не ответ. – Martijn Pieters♦ 20 October 2012 в 13:27
  • 2
    В принятом ответе уже упоминается об этом, и вы даже не пытались дать более подробную информацию об этом – Murmel 22 November 2015 в 17:20

127.0.1.1 - ваш реальный IP-адрес. В более общем плане компьютер может иметь любое количество IP-адресов. Вы можете отфильтровать их для частных сетей - 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12 и 192.168.0.0/16.

Однако нет кросс-платформенного способа получить все IP-адреса. В Linux вы можете использовать SIOCGIFCONF ioctl.

4
ответ дан phihag 22 August 2018 в 08:10
поделиться
  • 1
    Он означает его видимый снаружи IP. Диапазон 127. *. *. * Обычно относится к локальному хосту или внутренней сети, что явно не то, что он хочет. – Cerin 17 May 2012 в 19:59

Чтобы получить ip-адрес, вы можете использовать команду shell непосредственно в python:

import socket, subprocess

def getIpAndHostname():
    hostname =  socket.gethostname()

    shell_cmd = "ifconfig | awk '/inet addr/{print substr($2,6)}'"
    proc = subprocess.Popen([shell_cmd], stdout=subprocess.PIPE, shell=True)
    (out, err) = proc.communicate()

    ip_list = out.split('\n')
    ip = ip_list[0]

    for _ip in ip_list:
        try:
            if _ip != "127.0.0.1" and _ip.split(".")[3] != "1":
                ip = _ip
        except:
            pass
    return ip, hostname

ip_addr, hostname = getIpAndHostname()
3
ответ дан RiccardoCh 22 August 2018 в 08:10
поделиться
import netifaces as ni 

ni.ifaddresses('eth0')
ip = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
print(ip)

Это вернет вам IP-адрес в системе Ubuntu, а также MacOS. Результатом будет IP-адрес системы, как мой IP: 192.168.1.10.

2
ответ дан shinjw 22 August 2018 в 08:10
поделиться
  • 1
    netifaces не входит в стандартную библиотеку, и очень похожий ответ уже был опубликован. – Maximilian Peters 2 January 2018 в 16:30

im, используя следующий модуль:

#!/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

Протестировано с помощью окон и linux (и не требует дополнительных модулей для них), предназначенных для использования в системах, которые находятся в одной локальной сети на основе IPv4.

Фиксированный список имен интерфейсов не работает для последних версий Linux, которые приняли изменение systemd v197 относительно предсказуемых имен интерфейсов, как указано Alexander . В таких случаях вам нужно вручную заменить список именами интерфейса в вашей системе или использовать другое решение, например netifaces .

26
ответ дан smerlin 22 August 2018 в 08:10
поделиться

В 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'
>>> 
38
ответ дан tMC 22 August 2018 в 08:10
поделиться
  • 1
    Таким образом, это эффективно открывает сокет, в котором он ничего не делает, и вы проверяете необработанные данные об этом сокете, чтобы получить локальный IP-адрес? – Dave 14 November 2013 в 20:00
  • 2
  • 3
    Работает на Python3 с одной модификацией: struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14) следует заменить на struct.pack('16sH14s', iface.encode('utf-8'), socket.AF_INET, b'\x00'*14) – pepoluan 3 January 2014 в 10:28
  • 4
    @ChristianFischer ioctl - это устаревший интерфейс, который, как мне кажется, не поддерживает IPv6 и, вероятно, никогда не будет. Я думаю, что «Правильный» способ - через Netlink, который не очень прост в Python. Я думаю, что libc должен иметь функцию getifaddrs, к которой можно получить доступ через модуль pythons ctypes, который может работать - man7.org/linux/man-pages/man3/getifaddrs.3.html – tMC 12 February 2014 в 17:37
  • 5
    @Maddy ioctl - это устаревший интерфейс. Я не верю, что поддерживает IPv6 и, вероятно, никогда не будет. Я думаю, что «Правильный» способ - через Netlink, который не очень прост в Python. Я думаю, что libc должен иметь функцию getifaddrs, к которой можно получить доступ через модуль pythons ctypes, который может работать - man7.org/linux/man-pages/man3/getifaddrs.3.html – tMC 2 April 2014 в 13:57

netifaces доступен через pip и easy_install.

netifaces имеет некоторые странности на разных платформах:

  • Интерфейс localhost / loop-back может не всегда включаться (Cygwin).
  • Адреса указаны для каждого протокола (например, IPv4, IPv6), а протоколы перечислены для каждого интерфейса. В некоторых системах (Linux) каждая пара протокольных интерфейсов имеет свой собственный связанный интерфейс (с использованием нотации interface_name: n), а в других системах (Windows) один интерфейс будет иметь список адресов для каждого протокола. В обоих случаях есть список протоколов, но он может содержать только один элемент.

Вот какой код netifaces для воспроизведения:

import netifaces

PROTO = netifaces.AF_INET   # We want only IPv4, for now at least

# Get list of network interfaces
# Note: Can't filter for 'lo' here because Windows lacks it.
ifaces = netifaces.interfaces()

# Get all addresses (of all kinds) for each interface
if_addrs = [netifaces.ifaddresses(iface) for iface in ifaces]

# Filter for the desired address type
if_inet_addrs = [addr[PROTO] for addr in if_addrs if PROTO in addr]

iface_addrs = [s['addr'] for a in if_inet_addrs for s in a if 'addr' in s]
# Can filter for '127.0.0.1' here.

Вышеприведенный код не отображает адрес обратно в его имя интерфейса (полезно для генерации правил ebtables / iptables на лету). Итак, вот версия, которая хранит вышеуказанную информацию с именем интерфейса в кортеже:

import netifaces

PROTO = netifaces.AF_INET   # We want only IPv4, for now at least

# Get list of network interfaces
ifaces = netifaces.interfaces()

# Get addresses for each interface
if_addrs = [(netifaces.ifaddresses(iface), iface) for iface in ifaces]

# Filter for only IPv4 addresses
if_inet_addrs = [(tup[0][PROTO], tup[1]) for tup in if_addrs if PROTO in tup[0]]

iface_addrs = [(s['addr'], tup[1]) for tup in if_inet_addrs for s in tup[0] if 'addr' in s]

И нет, я не влюблен в понимание списков. Это как раз то, как мой мозг работает в наши дни.

Следующий фрагмент распечатает все:

from __future__ import print_function  # For 2.x folks
from pprint import pprint as pp

print('\nifaces = ', end='')
pp(ifaces)

print('\nif_addrs = ', end='')
pp(if_addrs)

print('\nif_inet_addrs = ', end='')
pp(if_inet_addrs)

print('\niface_addrs = ', end='')
pp(iface_addrs)

Наслаждайтесь!

3
ответ дан user3712955 22 August 2018 в 08:10
поделиться
  • 1
    netifaces действительно облегчает жизнь во время решения этой проблемы. – Drake Guan 20 November 2014 в 05:53

Этот ответ - моя личная попытка решить проблему получения IP-адреса LAN, так как socket.gethostbyname(socket.gethostname()) также возвратил 127.0.0.1. Этот метод не требует Интернета только для подключения к локальной сети. Код для Python 3.x, но может быть легко преобразован для 2.x. Использование UDP Broadcast:

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())
5
ответ дан WolfRage 22 August 2018 в 08:10
поделиться
  • 1
    Что произойдет, если вы запускаете это одновременно на двух машинах в одной сети? Когда вы передаете свое сообщение в сети, все машины получат «Что такое IP-адрес вашей локальной сети. Ваш udp_listening_server может ответить на ваш IP-адрес: xxx. – Nicolas Defranoux 21 January 2015 в 12:47

Я только что нашел это, но кажется немного взломанным, однако они говорят, что попробовали его на * nix, и я сделал это на окнах, и это сработало.

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
print(s.getsockname()[0])
s.close()

Предполагается, что у вас есть доступ в Интернет, и что нет локального прокси.

344
ответ дан Zags 22 August 2018 в 08:10
поделиться
  • 1
    Приятно, если у вас есть несколько интерфейсов на машине, и вам нужен тот, который маршрутизирует, например. gmail.com – elzapp 20 October 2010 в 15:16
  • 2
    Может быть хорошей идеей поймать исключения socket.error, которые могут быть подняты s.connect ()! – phobie 14 October 2011 в 15:52
  • 3
    Было бы лучше использовать IP-адрес вместо имени домена - он должен быть более быстрым и независимым от доступности DNS. Например. мы можем использовать 8.8.8.8 IP - общедоступный DNS-сервер Google. – rslnx 16 April 2012 в 13:27
  • 4
    Хорошо, этот метод отлично работает как на Linux, так и на Windows – feisky 24 August 2012 в 03:14
  • 5
    Очень умный, отлично работает. Вместо gmail или 8.8.8.8 вы также можете использовать IP-адрес или адрес сервера, с которого вы хотите видеть, если это применимо. – Prof. Falken 22 August 2013 в 09:07
Другие вопросы по тегам:

Похожие вопросы: