Поиск локальных IP-адресов с помощью Python stdlib

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

Локальный IP? Или публичный IP? Как вы собираетесь работать с системами с несколькими IP-адресами?

Sargun Dhillon 05.11.2008 20:29

используйте ifconfig -a и используйте вывод оттуда ...

Fredrik Pihl 23.06.2011 15:18

@ Фредрик Это плохая идея. Прежде всего, вы без необходимости создаете новый процесс, и это может помешать вашей программе работать в жестко заблокированных конфигурациях (или вам придется разрешить права, которые вашей программе не нужны). Во-вторых, вы познакомитесь с ошибками для пользователей из разных стран. В-третьих, если вы вообще решаете запустить новую программу, вы не должны запускать устаревшую - ip addr гораздо более подходит (и его легче разбирать, загружать).

phihag 23.06.2011 17:07

@phihag ты абсолютно прав, спасибо что поправили мою глупость

Fredrik Pihl 25.06.2011 00:16

Более фундаментальная проблема здесь заключается в том, что в правильно написанной современной сетевой программе правильный (набор) локальных IP-адресов зависит от однорангового узла или набора потенциальных одноранговых узлов. Если локальный IP-адрес необходим для bind сокета для определенного интерфейса, то это вопрос политики. Если локальный IP-адрес необходим для передачи его одноранговому узлу, чтобы одноранговый узел мог «перезвонить», то есть для открытия соединения обратно с локальной машиной, тогда ситуация зависит от наличия NAT (трансляции сетевых адресов). коробки между ними. Если нет NAT, getsockname - хороший выбор.

Pekka Nikander 30.04.2012 08:58
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
584
5
742 915
46
Перейти к ответу Данный вопрос помечен как решенный

Ответы 46

Ответ принят как подходящий

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

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

Следует отметить, что это не платформенно-независимое решение. Многие Linux вернут 127.0.0.1 в качестве вашего IP-адреса, используя этот метод.

Jason Baker 03.10.2008 16:07

Вариант: socket.gethostbyname (socket.getfqdn ())

gimel 03.10.2008 16:08

Похоже, что это возвращает только один IP-адрес. Что делать, если у машины несколько адресов?

Jason R. Coombs 23.10.2009 18:39

В Ubuntu по какой-то причине возвращается 127.0.1.1.

slikts 20.03.2012 09:52

@Reinis I: в Ubuntu это возвращает 127.0.1.1 из-за строки в / etc / hosts. Эту линию можно удалить без страшных последствий.

amarillion 24.09.2012 12:50

Не полагайтесь на DNS (и, возможно, вызывайте блокировку сетевого ввода-вывода), если все, что вам нужно знать, - это локальное имя хоста.

Glenn Maynard 28.02.2013 23:17

@amarillion Я обнаружил, что rabbitmq недоволен, если эта строка отсутствует в / etc / hosts

Lorin Hochstein 21.06.2013 06:43

@amarillion: В некоторых системах Ubuntu [какие?] пользователь может потерять возможность запускать команды sudo, если 127.0.1.1 отсутствует в файле hosts. У меня такое случалось, и это задокументировано.

dotancohen 21.11.2013 19:26

@UnkwnTech, пожалуйста, не принимайте ответ, это явно ненадежно.

Federico 07.01.2015 15:41

@ Джейсон Р. Кумбс, используйте следующий код для получения списка адресов IPv4, принадлежащих хост-машине: socket.gethostbyname_ex(socket.gethostname())[-1]

Barmaley 15.05.2015 23:36

Этот работает, если вы знаете интерфейс: stackoverflow.com/a/24196955/385482

stanga 09.06.2015 17:59

Это может быть проблемой и в Windows, потому что у меня есть VirtualBox, который устанавливает собственный сетевой адаптер. Команда socket.gethostbyname(socket.gethostname()) вернула адрес Virtualbox. Ответ @ JasonR.Coombs был полезен, потому что он вернул оба. VirtualBox первый на моем, но я не знаю, как он решает порядок

TimSmith-Aardwolf 26.07.2015 18:28

Ой. Понятия не имею, почему этот ответ был принят. Пожалуйста, люди, просто используйте уловку «подключитесь к 8.8.8.8 и получите локальный адрес этого сокета». По крайней мере, это гарантированно работает.

Matthias Urlichs 15.11.2015 20:59

он работает, только если есть один сетевой интерфейс, если у вас несколько, например Ethernet и беспроводной, он показывает неправильный IP-адрес при подключении к беспроводной сети. используйте другие ответы, которые используют метод getsockname (), чтобы получить правильный IP-адрес

RAFIQ 20.11.2015 07:45

Очень мило, вы спасаете жизнь !! : D

Jcc.Sanabria 28.03.2017 21:48

В Ubuntu 17.10 даже ответ @ gimel возвращает "127.0.0.1"

code 11.04.2018 14:40

Каждое использование socket.getfqdn() приводит к задержке на моей платформе в 8-10 секунд. (Я использую Windows в большой корпоративной сети.)

JDM 28.08.2018 14:42

вернуть '127.0.0.1'

leon wu 11.04.2019 09:36

Например, это не возвращает адреса VPN.

Gerard 05.05.2020 14:45

У меня есть опция, которая может отфильтровывать IPv6 и локальные адреса обратной связи / ссылки, а также проверять, является ли вывод действительным IP. stackoverflow.com/questions/24196932/…

Geruta 26.10.2020 04:38

Я использую AWS EC2, и мне пришлось использовать модификацию ответа @Barmaley: socket.gethostbyname_ex(socket.gethostname())[-1][-1]

Chris Wolf 04.02.2021 17:17

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

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

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

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

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

Хорошо, если у вас есть несколько интерфейсов на машине, и вам нужен тот, который, например, gmail.com

elzapp 20.10.2010 18:16

Было бы неплохо перехватить исключения socket.error, которые могут быть вызваны s.connect ()!

phobie 14.10.2011 18:52

Хорошо, я все равно хочу, чтобы IP-адрес видел какой-то клиент при подключении к моей службе.

Olson 15.04.2012 20:15

Лучше использовать IP-адрес вместо доменного имени - он должен быть быстрее и не зависеть от доступности DNS. Например. мы можем использовать 8.8.8.8 IP - публичный DNS-сервер Google.

wobmene 16.04.2012 16:27

Очень умно, отлично работает. Вместо gmail или 8.8.8.8 вы также можете использовать IP или адрес сервера, с которого вы хотите, чтобы вас видели, если это применимо.

Prof. Falken 22.08.2013 12:07

@ Проф. Фалькен Ага! Он отлично работает и в локальной сети. Вы можете подключиться практически к любой машине, прослушивающей указанный порт. Мне нужно было использовать IP-адрес сервера в качестве ключа для набора Redis, поэтому я просто использовал сервер и порт Redis для получения IP-адреса, и это сработало как шарм! :-)

KyleFarris 20.09.2013 07:06

как заставить это работать с широковещательными адресами вместо gmail.com?

Jayen 04.12.2013 09:09

Мне это нравится. Мне бы лучше, если бы я мог выяснить, как использовать IP-адрес туннеля vpn.

Epu 10.12.2013 03:55

человек, использование подключения к сокету UDP ничего не дает. Но он дает сокету общедоступный IP-адрес. Я использовал s.connect (("123.123.123.123", 80))

Rui Botelho 03.04.2015 16:21

В этом примере есть внешняя зависимость от возможности фактического разрешения gmail.com. Если вы установите для него IP-адрес, который не находится в вашей локальной сети (не имеет значения, работает он или нет), он будет работать без зависимостей и без сетевого трафика.

grim 11.05.2015 21:29

Как отметил @grim, было бы лучше открыть сокет с наиболее вероятным доступным компьютером, поскольку многие сетевые устройства не имеют бесплатного доступа к Интернету. Я думаю, что ваш шлюз или DHCP-сервер могут быть лучшими. Вы можете получить свой шлюз в Linux с помощью stackoverflow.com/a/6556951/1411638

Sdlion 17.09.2015 19:24

@feisky Я только что подтвердил, что это также работает на OSX (под управлением El Capitan)

Josep Valls 12.01.2016 23:00

Умно, таким образом можно найти правильный IP-адрес интерфейса для указанного хоста назначения и без фактической отправки какого-либо пакета.

adamhj 03.08.2016 04:00

Чтобы добавить к комментариям за 9 лет: это решение просто работало для меня на автономном процессоре под управлением Yocto Linux в 2017 году.

Snesticle 11.04.2017 01:08

Это решение работает, но я предпочитаю не использовать IP-адрес Google (8.8.8.8), а, как указал Джеймисон Беккер, например, s.connect(('10.255.255.255', 1)).

np8 21.07.2017 22:34

Сокеты SOCK_DGRAM (UDP) не поддерживают connect. Поэтому вам следует придерживаться какого-то TCP-адреса

yanpas 20.09.2017 18:41

Как я предлагал в отвечать за 3 года до последнего обновления, вы можете заменить конкретное имя порта на s.connect (('<broadcast>', 0)), но сначала вам нужно вызвать s.setsockopt (socket.SOL_SOCKET , socket.SO_BROADCAST, 1)

dlm 04.05.2018 18:42

@yanpas "Сокеты SOCK_DGRAM (UDP) не поддерживают соединение. Поэтому вам следует придерживаться какого-то TCP-адреса". Не правда

dlm 04.05.2018 18:46

Использование '<broadcast>' имеет преимущества: (а) отсутствие необходимости подключения к Интернету и (б) отсутствие необходимости знать какие-либо номера портов в локальной сети.

dlm 04.05.2018 18:51

Это самое умное решение, которое я когда-либо видел, и, судя по комментариям, прошедшими испытания на протяжении многих лет, оно кажется проверенным. Чтобы еще больше отполировать его, я предлагаю использовать порт 53 с udp для сервера имен, например 8.8.8.8, и порт 9 (протокол сброса rfc 863) с udp / tcp для произвольных хостов других типов.

Compl Yue 24.04.2019 10:36

В моей книге хакерство не означает, что что-то плохо, если оно работает хорошо и все еще может быть понято.

The Daleks 23.04.2020 02:15

На самом деле для этого вообще не требуется доступ в Интернет, только подключение к сети. Он просто попытается найти 8.8.8.8. Может кто-нибудь это подтвердить? если да, то можно было бы отредактировать ответ

Gerard 26.05.2020 12:48

Очень полезно, особенно когда установлен net-tools, но по какой-то загадочной причине не может работать ifconfig. Вы можете узнать свой локальный IP-адрес с помощью всего нескольких строк кода. Python просто потрясающий.

Mark 17.09.2020 20:21

Вы можете использовать модуль 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.

Как указано в вопросе, я хочу что-то от установки по умолчанию, так как дополнительных установок не требуется.

UnkwnTech 03.10.2008 16:52

@MattJoiner Ни то, ни другое уже не соответствует действительности (последняя версия имеет двоичные файлы Windows на PyPI и поддерживает Py3K).

alastair 02.05.2014 19:42

@ Jean-PaulCalderone FWIW, последняя версия netifaces делает поддерживает IPv6 в Windows.

alastair 02.05.2014 19:43

этот модуль должен быть частью стандартной библиотеки, учитывая, что python утверждает философию `` батарейки включены ''

ccpizza 22.10.2017 11:42

поднять ошибку, может быть, он будет включен в sys, кажется, хороший кандидат для этого.

Jasen 24.11.2017 06:53

@MattJoiner - обратите внимание, что в Ubuntu последняя версия не требует компилятора C ни для python, ни для Py3K. И для модуля тоже есть пакеты.

Craig S. Anderson 30.05.2019 06:59

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

Приведенное выше решение с одним лайнером обычно работает с окнами. Проблема в Linux.

ricree 18.06.2009 04:19

+1 Эта техника как минимум пытается вернуть все адреса на машине.

Jason R. Coombs 23.10.2009 18:42

Этот сценарий не работает на моей машине после возврата первого адреса. Ошибка: «AttributeError: объект 'LP_IP_ADDR_STRING' не имеет атрибута 'ipAddress'». Я подозреваю, что это как-то связано с IPv6-адресом.

Jason R. Coombs 23.10.2009 18:43

Оказывается, проблема в том, что для чего-либо, кроме первого IP-адреса, adNode не разыменовывается. Добавьте еще одну строчку в пример в цикле while, и она у меня сработает: adNode = adNode.contents

Jason R. Coombs 23.10.2009 20:09

Как псевдоним myip, он должен работать везде:

alias myip = "python -c 'import socket; print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith(\"127.\")][:1], [[(s.connect((\"8.8.8.8\", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])'"
  • Правильно работает с Python 2.x, Python 3.x, современными и старыми дистрибутивами Linux, OSX / macOS и Windows для поиска текущего IPv4-адреса.
  • Не вернет правильный результат для машин с несколькими IP-адресами, IPv6, без настроенного IP-адреса или без доступа в Интернет.

ПРИМЕЧАНИЕ: Если вы собираетесь использовать что-то подобное в программе Python, правильным способом является использование модуля Python с поддержкой IPv6.


То же, что и выше, но только код Python:

import socket
print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1], [[(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])
  • Это вызовет исключение, если IP-адрес не настроен.

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

import socket
print((([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")] or [[(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) + ["no IP found"])[0])

(спасибо @ccpizza)


Фон:

Использование socket.gethostbyname(socket.gethostname()) здесь не сработало, потому что на одном из компьютеров, на котором я был, был /etc/hosts с повторяющимися записями и ссылками на себя. socket.gethostbyname() возвращает только последнюю запись в /etc/hosts.

Это была моя первая попытка отсеять все адреса, начинающиеся с "127.":

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

Это работает с Python 2 и 3, в Linux и Windows, но не работает с несколькими сетевыми устройствами или IPv6. Однако он перестал работать в последних дистрибутивах Linux, поэтому вместо этого я попробовал эту альтернативную технику. Он пытается подключиться к DNS-серверу Google на 8.8.8.8 через порт 53:

import socket
print([(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1])

Затем я объединил два вышеуказанных метода в однострочник, который должен работать везде, и создал псевдоним myip и фрагмент кода Python в верхней части этого ответа.

С ростом популярности IPv6 и для серверов с несколькими сетевыми интерфейсами использование стороннего модуля Python для поиска IP-адреса, вероятно, является более надежным и надежным, чем любой из перечисленных здесь методов.

socket.gethostbyname_ex('') отлично работает, не полагаясь на имя хоста компьютера. Также случается, что указанное имя хоста возвращается в качестве первого элемента в кортеже. Итак, socket.gethostbyname_ex('')[2] по какой-то причине дает мне все мои локальные IP-адреса и / not / 127.0.0.1. Это на Python 2.6.6 32bit, Windows 7 64bit.

Mark Ribau 08.09.2011 07:58

Забыл отметить, что код в моем комментарии выше (не может больше редактировать) также дает мне IP-адреса VPN, что было важно для меня, когда я пришел сюда в поисках ответа.

Mark Ribau 08.09.2011 08:05

Странно, я не получаю IP-адреса VPN. (Это то, к чему я также пытаюсь получить доступ) Вышеупомянутое дает мне мой стандартный внутренний IP-адрес, но не IP-адрес для VPN, к которой я также подключен

kdbdallas 04.12.2011 11:25

kdbdallas, я не знаю, используете ли вы win / osx или Linux, но я думаю, что в этом контексте VPN-соединения обычно отображаются как отдельное сетевое устройство.

Alexander 05.12.2011 16:27

К сожалению, это не вернет адреса IPv6 - похоже, для этого вам понадобится socket.getaddrinfo(). Другими словами, ответ Накилона ниже даст вам лучшие результаты.

Wladimir Palant 01.10.2013 19:02

@ Владимир Палант, я уже упоминал об этом. Кроме того, его реализация может возвращать повторяющиеся IP-адреса. Он также не упоминает, работает ли он в Windows, OSX и Linux или нет.

Alexander 02.10.2013 18:28

@Alexander: Просто хочу сказать, что этот ответ гораздо менее полезен, чем раньше (и это не похоже на то, чтобы фильтровать дубликаты - это большое дело;). Согласно документации socket.getaddrinfo() должен стабильно работать на разных платформах, но я проверял его только на Linux, не беспокоился о других операционных системах.

Wladimir Palant 04.10.2013 11:01

@Alexander, /etc/resolve.conf: No such file or directory и у меня есть локальный IPv4-адрес, показанный ifconfig.

anatoly techtonik 16.12.2013 20:30

Я могу подтвердить, что обновленная версия работает с Ubuntu 14.04 как с Python2, так и с Py3k.

Uli Köhler 07.06.2014 02:55

«Обновление» демонстрирует хороший трюк с connect () на UDP-сокете. Он не отправляет трафик, но позволяет найти адрес отправителя для пакетов указанному получателю. Порт скорее всего не имеет значения (даже 0 должен работать). На многосетевом хосте важно выбрать адрес в правильной подсети.

Peter Hansen 14.06.2014 01:19

Вроде не могу подключиться к 8.8.8.8 по 80 порту - у кого-нибудь еще есть такая проблема? google.com с другой стороны работает нормально

Chris 04.02.2016 05:07

Крис, это сработает, если вы попробуете вместо этого использовать порт 53?

Alexander 05.02.2016 13:03

Я нашел этот ответ полезным и в конечном итоге использовал socket.gethostbyname_ex(socket.gethostname())[2], который работает для моих нужд, это двухуровневый Arch Linux и python2 / 3. Я не уверен, что мне не хватает, потому что я не использовал весь фрагмент, указанный в ответе.

starfry 28.09.2017 18:09

Я предполагаю, что вам будет не хватать только псевдонима в вашей конфигурации оболочки (который вы разделяете среди систем, к которым у вас есть доступ, независимо от ОС, я полагаю), который будет работать на всех из них при обычных обстоятельствах.

Alexander 28.09.2017 22:27

Комбинированный код псевдонима инициирует ненужное внешнее соединение с 8.8.8.8, даже если gethostbyname_ex вернул действительный IP-адрес. Это приведет к поломке локальных сетей типа «огороженный сад» без интернета. Внешний вызов можно сделать условным с помощью or, например: ips = [ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")] or [[(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]

ccpizza 22.10.2017 12:47

просто потому, что вы можете написать этот код в одной строке, это не значит, что вы должны ...

JackLeo 03.01.2018 14:01

@JackLeo Он работает как псевдоним в командной строке. Если вы хотите сделать это правильно, вам следует в первую очередь использовать модуль Python, который правильно обрабатывает IPv6 и несколько сетевых интерфейсов.

Alexander 03.01.2018 14:09

Было бы намного лучше, если бы у вас была не-одинарная версия. Я хочу использовать это в скрипте Python, а не в соревнованиях по гольфу.

Fake Name 25.08.2018 10:18

Правильный способ - использовать модуль Python с поддержкой IPv6, а не какие-либо ответы на этой странице.

Alexander 19.09.2019 11:08

Я думаю, что однострочник - это круто - конечно, вы можете очистить его для реального использования. Он работает на AWS EC2 под управлением AMI на базе CentOS, спасибо.

Chris Wolf 04.02.2021 17:25

Я использую следующий модуль:

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

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

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

Это несовместимо с новыми предсказуемыми именами интерфейсов Linux, такими как enp0s25. Для получения дополнительной информации см. wiki.archlinux.org/index.php/Network_Configuration#Device_na‌ mes.

Alexander 25.04.2014 15:54

Я использовал python 3.4, и часть 'struct.pack (...)' нужно было изменить на 'struct.pack (' 256s ', bytes (ifname [: 15],' utf-8 '))'. См. Этот вопрос: stackoverflow.com/q/27391167/76010

Bakanekobrain 06.03.2015 03:09

на Raspbian с Python 2.7.3 - bytes () не понравился второй аргумент. Но это сработало: struct.pack('256s', bytes(ifname[:15]))

colm.anseo 17.10.2015 21:57

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

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

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

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

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

Красиво и просто. Также работает с AMI Linux от Amazon, но только если я root. В противном случае я бы получил сообщение об ошибке: 'sh: ifconfig: command not found'

IgorGanapolsky 10.11.2010 19:52

Поэтому вы должны использовать "/ sbin / ifconfig", как сказал Гавалет. Он также работает в Red Hat 4.1.2-48.

IgorGanapolsky 10.11.2010 20:05

Устарело с версии 2.6. Используйте модуль подпроцесса для выполнения команд.

Colin Dunklau 19.03.2013 01:06

И ifconfig также устарел. Используйте iproute2.

Helmut Grohne 09.04.2013 17:04

Получите все IP-адреса: import sh; [ip.split () [1] [5:] для ip в фильтре (лямбда x: 'inet addr' в x, sh.ifconfig (). split ("\ n"))]

Gabriel Littman 28.02.2014 02:43

это дает мне localhost 127.0.0.1 ip на raspbian

nwgat 19.03.2016 18:53

Как мы узнаем, что выходной формат ipconfig никогда не меняется?

Thomas Weller 03.08.2016 17:33

потому что это устарело!

Jasen 24.11.2017 06:57

Чтобы получить список IP-адресов в системах * nix,

import subprocess
co = subprocess.Popen(['ifconfig'], stdout = subprocess.PIPE)
ifconfig = co.stdout.read()
ip_regex = re.compile('((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-4]|2[0-5][0-9]|[01]?[0-9][0-9]?))')
[match[0] for match in ip_regex.findall(ifconfig, re.MULTILINE)]

Хотя это немного поздно для этого ответа, я подумал, что кому-то это может пригодиться :-)

PS: Он также вернет широковещательные адреса и сетевую маску.

FWIW, я считаю hostname -i и hostname -I (обратите внимание на заглавную i) более простой альтернативой ifconfig. Версия с заглавной буквы возвращает все адреса, а в нижнем регистре - значение «по умолчанию», которое может быть 127.0.1.1 (т.е. бесполезно).

RobM 04.04.2011 22:02

имя хоста -I (с большой буквы) недоступно в старых версиях различных операционных систем. Например, CentOS 5.2. Итак, я полагаю, что приведенный выше сценарий следует предпочесть на всякий случай. PS: Спасибо за комментарий. Команда полезна для последних версий ОС.

Kulbir Saini 30.04.2011 10:13

Следует отметить, что использование имени хоста, предложенное Робом, специфично для Linux. Например, Solaris с радостью изменит ваше имя хоста на "-I", если вы вызовете команду, заданную как root.

Eli Heady 23.11.2011 05:19

Спасибо за эту заметку @EliHeady, которая спасла миллионы жизней: D

Phyo Arkar Lwin 28.02.2012 18:10

Один простой способ произвести "чистый" вывод с помощью утилит командной строки:

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

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

Он не покажет все адреса IPv4, потому что ifconfig сообщает вам только об основных. Вам нужно использовать ip из iproute2, чтобы увидеть все адреса.

Helmut Grohne 09.04.2013 17:02

Это чертовски много оболочки для вопроса о стандартной библиотеке ... Кроме того, синтаксический анализ ifconfig не является переносимым и даже не будет надежно работать на одной машине.

Dominik George 12.09.2017 10:42

У машины может быть несколько сетевых интерфейсов (включая локальный шлейф 127.0.0.1), о котором вы упомянули. Что касается ОС, то это еще и «настоящий IP-адрес».

Если вы хотите отслеживать все интерфейсы, взгляните на следующий пакет Puthon: http://alastairs-place.net/netifaces/

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

как получить этот модуль netifaces?

rɑːdʒɑ 22.03.2014 16:55

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.

Он имеет в виду свой видимый извне IP. Диапазон 127. *. *. * Обычно относится к localhost или внутренней сети, что явно не то, что ему нужно.

Cerin 17.05.2012 22:59

Метод Socket API

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

Минусы:

  • Не кроссплатформенный.
  • Требуется дополнительный резервный код, связанный с наличием определенных адресов в Интернете.
  • Это также не сработает, если вы находитесь за NAT.
  • Вероятно, создает UDP-соединение, не независимо от доступности DNS (обычно ISP) (см. Другие ответы на такие идеи, как использование 8.8.8.8: сервер Google (по совпадению также DNS))
  • Убедитесь, что вы сделали адрес назначения НЕДОСТУПНЫМ, как числовой 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 (чтобы предотвратить атаку типа `` злоумышленник посередине ''). быть сервером)

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

Это вернет ваш адрес в локальной сети, если вы находитесь за NAT. Если вы подключаетесь к Интернету, вы можете подключиться к веб-службе, которая возвращает один из ваших общедоступных IP-адресов.

phihag 23.06.2011 15:10

Он не создает TCP-соединение, потому что он создает UDP-соединение.

Anuj Gupta 26.03.2013 20:41

В качестве альтернативы в версии API сокетов замените s.connect (('INSERT SOME TARGET WEBSITE.com', 0)) на s.setsockopt (socket.SOL_SOCKET, socket.SO_BROADCAST, 1); s.connect (('< broadcast> ', 0)), чтобы избежать поиска в DNS. (Думаю, может быть проблема с трансляцией, если есть брандмауэр)

dlm 12.08.2013 07:55

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

Таким образом, это эффективно открывает сокет, с которым он ничего не делает, и вы проверяете необработанные данные об этом сокете, чтобы получить локальный IP-адрес?

Dave 14.11.2013 22:00

Сокет открывается, чтобы получить fd для связи с ядром (через ioctl). Сокет не привязан к интерфейсу, для которого вы хотите получить информацию об адресе - это просто механизм связи между пользовательским пространством и ядром. en.wikipedia.org/wiki/Ioctllxr.free-electrons.com/source/net/socket.c

tMC 15.11.2013 00:04

Работает на Python3 с одной модификацией: struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14) следует заменить на struct.pack('16sH14s', iface.encode('utf-8'), socket.AF_INET, b'\x00'*14).

pepoluan 03.01.2014 12:28

как я могу сделать то же самое для ipv6?

cfischer 06.02.2014 17:23

@ChristianFischer ioctl - это устаревший интерфейс, который, по моему мнению, не поддерживает IPv6 и, скорее всего, никогда не будет. Я думаю, что «правильный» путь - через Netlink, что не очень просто в Python. Я думаю, что libc должна иметь функцию getifaddrs, к которой можно получить доступ через модуль pythons ctypes, который может работать - man7.org/linux/man-pages/man3/getifaddrs.3.html

tMC 12.02.2014 19:37

@Maddy ioctl - это устаревший интерфейс, который, по моему мнению, не поддерживает IPv6 и, скорее всего, никогда не будет. Я думаю, что «правильный» путь - через Netlink, что не очень просто в Python. Я думаю, что libc должна иметь функцию getifaddrs, к которой можно получить доступ через модуль pythons ctypes, который может работать - man7.org/linux/man-pages/man3/getifaddrs.3.html

tMC 02.04.2014 16:57

Это хорошо, потому что не требует подключения к Интернету.

jtpereyda 17.10.2015 02:15

Хорошо, так что это специфично для Windows и требует установки модуль WMI Python, но это кажется гораздо менее хакерским, чем постоянные попытки вызвать внешний сервер. Это просто еще один вариант, так как хороших вариантов уже много, но он может хорошо подойти для вашего проекта.

Import WMI

def getlocalip():
    local = wmi.WMI()
    for interface in local.Win32_NetworkAdapterConfiguration(IPEnabled=1):
        for ip_address in interface.IPAddress:
            if ip_address != '0.0.0.0':
                localip = ip_address
    return localip







>>>getlocalip()
u'xxx.xxx.xxx.xxx'
>>>

Между прочим, WMI очень мощный ... если вы занимаетесь удаленным администрированием оконных машин, вам обязательно нужно проверить, что он может.

Мне пришлось решить задачу «Выяснить, является ли 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

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

Это будет работать на большинстве ящиков 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()

Небольшое уточнение версии команд, которая использует команду 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)]

import socket
socket.gethostbyname(socket.getfqdn())

Вместо того, чтобы просто публиковать блок кода, пожалуйста, объяснять, почему этот код решает поставленную проблему. Без объяснения причин это не ответ.

Martijn Pieters 20.10.2012 16:27

В принятом ответе уже упоминается об этом, и вы даже не пытались дать более подробную информацию об этом.

Murmel 22.11.2015 19:20

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

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

Что произойдет, если вы запустите это одновременно на двух машинах в одной сети? Когда вы транслируете свое сообщение в сети, все машины получат «Какой у меня IP-адрес в локальной сети. Ваш udp_listening_server может ответить на сообщение "ваш IP-адрес xxx".

Nicolas Defranoux 21.01.2015 14:47

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

Хм ... на сервере с двумя сетевыми адаптерами это дает один назначенных IP-адресов, но повторяется три раза. На моем ноутбуке выдает 127.0.1.1 (повторяется три раза ...) ...

bryn 20.11.2013 17:30

Дает мне ['fe80::34e8:fe19:1459:2cde%22','fe80::d528:99fb:d572:e289%1‌​2', '192.168.56.1', '192.168.1.2'] на рабочем столе Windows.

Nakilon 19.07.2014 07:48

Примечание: это не использование стандартной библиотеки, но довольно простое.

$ pip install pif

from pif import get_public_ip
get_public_ip()

вопросы касались поиска IP с помощью stdlib

Alexandru Chirila 03.09.2013 17:09

Что ж, вы можете использовать команду «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'])

Просто, но мило!

def getip():

    import socket
    hostname= socket.gethostname()
    ip=socket.gethostbyname(hostname)

    return(ip)

никогда не делал. всего два цента

Matt 09.12.2013 06:49

не работает, как упоминалось выше на ubuntu

lxx 18.11.2014 06:47

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

# imports
import errno
import socket
import logging

# 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:
        # log.info("trapped error connecting to %r via %r", remote, family, exc_info=True)
        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

Я подумал, что это мог быть действительно хороший ответ .. но он всегда возвращает None

Jamie Lindsey 27.01.2020 19:31

@JamieLindsey У вас есть какие-нибудь подробности о вашей ОС и конфигурации сети? Кроме того, что возвращает что-то вроде get_local_addr(remove = "www.google.com")? Регистрация socket.error, сгенерированного _get_local_addr (), может помочь в диагностике.

Eli Collins 28.01.2020 23:07

Вариант ответа ниндзягеко. Это должно работать в любой локальной сети, которая разрешает широковещательную передачу 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())

Подождите, а как <broadcast> - действительное имя хоста? !! Сколько из этих словесных имен хостов допустимы?

Dev Aggarwal 24.02.2019 14:21

Это работает для меня на Ubuntu 20.04 - получение 192.168.0.24, а не 127.0.0.1

Lewis Morris 08.06.2020 23:18

Работает на всех системах, на которых я его тестировал. Windows, Android, Linux, Mac.

dlm 19.06.2020 00:48

Когда я использую <broadcast> в Windows 10, я получаю IP-адрес беспроводной сетевой карты. Когда я использую 10.255.255.255, я получаю IP-адрес адаптера Ethernet TAP. Оба действительны. Но результаты разные, лол.

RandomB 13.12.2020 13:25

netifaces доступен через pip и easy_install. (Я знаю, его нет в базе, но, возможно, стоит установить.)

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

  • Интерфейс localhost / loop-back не всегда может быть включен (Cygwin).
  • Адреса перечислены для каждого протокола (например, IPv4, IPv6), а протоколы перечислены для каждого интерфейса. В некоторых системах (Linux) каждая пара протокол-интерфейс имеет свой собственный связанный интерфейс (с использованием нотации имя_интерфейса: 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)

Наслаждаться!

netifaces действительно значительно облегчает жизнь при решении этой проблемы.

Drake Guan 20.11.2014 07:53

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

import commands

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

На MS Windows (проверено)

import socket

socket.gethostbyname(socket.gethostname())

Не работает на macOS: hostname: illegal option -- I\nusage: hostname [-fs] [name-of-host]

Derek 朕會功夫 17.11.2017 04:57

В python 3 вам нужно заменить «команды» на «подпроцесс», остальное то же самое.

Miguel El Merendero 25.11.2020 17:13

Если у компьютера есть маршрут к Интернету, всегда будет работать для получения предпочтительного локального IP-адреса, даже если / etc / hosts установлен неправильно.

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 1))  # connect() for UDP doesn't send packets
local_ip_address = s.getsockname()[0]

Как это работает ? , 8.8.8.8 - это DNS-сервер Google, можем ли мы это сделать с локальным DNS-сервером?

Ciasto piekarz 07.04.2020 00:22

Версия, которая, как мне кажется, еще не была опубликована. Я тестировал 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'

Работает на Python3, Ubuntu 18.04; Строка должна быть байтами: >>> socket.inet_ntoa (fcntl.ioctl (s.fileno (), 0x8915, struct.pack ('256s', 'enp0s31f6' [: 15] .encode ('utf-8') )) [20:24]) '192.168.1.1'

cessor 28.07.2018 16:34

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

  • НЕ требует маршрутизируемого доступа к сети или какого-либо соединения вообще.
  • Работает, даже если все интерфейсы отключены от сети.
  • НЕ нужно и даже не пытается получить где-нибудь еще.
  • Работает с NAT, общедоступными, частными, внешними и внутренними IP-адресами
  • Чистый Python 2 (или 3) без внешних зависимостей.
  • Работает в Linux, Windows и OSX.

Python 3 или 2:

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 Exception:
        IP = '127.0.0.1'
    finally:
        s.close()
    return IP

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

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

Работает в Raspbian с Python 2 и 3!

pierce.jason 23.09.2015 20:03

Блестяще. Работает на Win7,8,8.1 + Linux Mint & Arch, включая виртуальные машины.

shermy 03.03.2016 03:07

Работает в Windows 10 Pro! Спасибо, Джеймисон Беккер!

varantes 12.04.2017 17:02

По какой-то причине это не работает в 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.04.2017 09:36

Это должен быть принятый ответ. socket.gethostbyname(socket.gethostname()) дает ужасные результаты.

Jason Floyd 15.10.2018 21:19

Mac OSX 10.14.3 (18D109) возвращает 127.0.0.1 в качестве основного IP-адреса, если нет маршрута к Интернету, но маршрутизатор назначает IP-адрес локальной сети через DHCP. По-прежнему может быть назначен 192.168.1.x, который будет действительным и, вероятно, предпочтительным адресом LAN.

Rich Andrews 23.03.2019 05:06

@RichAndrews Эта ситуация обсуждается в ответе: «Это возвращает единственный IP-адрес, который является основным (с маршрутом по умолчанию)». 127.0.0.1 будет ожидаемым ответом, если у вас нет маршрута в Интернет.

fatal_error 12.04.2019 09:47

Будет ли это работать с любым IP-адресом частная сеть? Например. 10.0.0.0 у меня тоже работает.

djvg 16.12.2020 23:40

Работает с AMI на базе AWS EC2. На MacOS-10.14, подключенном к корпоративной VPN, возвращает IP-адрес с интерфейса utun1 (предположим, что это VPN-IP)

Chris Wolf 04.02.2021 17:35

Это не очень похоже на Pythonic, но надежно работает в Windows.

def getWinIP(version = 'IPv4'):
    import subprocess
    if version not in ['IPv4', 'IPv6']:
        print 'error - protocol version must be "IPv4" or "IPv6"'
        return None
    ipconfig = subprocess.check_output('ipconfig')
    my_ip = []
    for line in ipconfig.split('\n'):
        if 'Address' in line and version in line:
            my_ip.append(line.split(' : ')[1].strip())
    return my_ip

print getWinIP()

Да, это хакерство, но временами я не чувствую себя сомневающимся в операционной системе, а просто продолжаю использовать то, что встроено и работает.

Версия Python 3.4, использующая недавно представленный пакет asyncio.

async get_local_ip():
    loop = asyncio.get_event_loop()
    transport, protocol = await loop.create_datagram_endpoint(
        asyncio.DatagramProtocol,
        remote_addr=('8.8.8.8', 80))
    result = transport.get_extra_info('sockname')[0])
    transport.close()
    return result

Это основано на отличный ответ UnkwnTech.

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

import socket, subprocess

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

    shell_cmd = "ifconfig | awk '/inet addr/{print substr(,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 = get_ip_and_hostname()

Обратите внимание, что ifconfig устарел - даже когда этот ответ был написан в 2016 году, он не поддерживал все доступные типы сокетов и адресов ядра и мог незаметно скрывать вещи (например, вторичные адреса, которые не привязаны к именованным псевдонимам), которые более новые инструменты iproute2 (например, ip addr list) могут показывать.

Charles Duffy 29.11.2020 22:58

Я решил использовать службу и / или API ipfy: https://www.ipify.org.

#!/usr/bin/env python3
from urllib.request import urlopen


def public_ip():
    data = urlopen('https://api.ipify.org').read()
    return str(data, encoding='utf-8')


print(public_ip())

Ответ также можно получить в форматах JSON и JSONP.

На Github есть ipifyБиблиотека Python.

Это очень похоже на ранее опубликованные ответы, но я не смог найти ни одного с таким использованием вызовов. Это то, что я использую для ipv4. Для ipv6 измените "." в ":" в

import socket
print next(i[4][0] for i in socket.getaddrinfo(
    socket.gethostname(), 80) if '127.' not in i[4][0] and '.' in i[4][0]);"

from netifaces import interfaces, ifaddresses, AF_INET
iplist = [ifaddresses(face)[AF_INET][0]["addr"] for face in interfaces() if AF_INET in ifaddresses(face)]
print(iplist)
['10.8.0.2', '192.168.1.10', '127.0.0.1']

netifaces не входит в стандартную библиотеку.

Dominik George 12.09.2017 10:39

import socket
print(socket.gethostbyname(socket.getfqdn()))

Разница, которую вы опубликовали, сбивает с толку, поскольку она не имеет ничего общего с какой-либо IDE. Это интерактивная оболочка Python против сценария.

Dominik George 12.09.2017 10:35

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.

netifaces не является частью стандартной библиотеки, и очень похожий ответ уже был опубликован.

Maximilian Peters 02.01.2018 18:30

Если вы ищете IPV4-адрес, отличный от IP-адреса вашего локального хоста 127.0.0.1, вот изящный фрагмент кода Python:

import subprocess
address = subprocess.check_output(['hostname', '-s', '-I'])
address = address.decode('utf-8') 
address=address[:-1]

Что также можно записать одной строкой:

address = subprocess.check_output(['hostname', '-s', '-I']).decode('utf-8')[:-1]

Даже если вы поместите localhost в /etc/hostname, код все равно предоставит ваш локальный IP-адрес.

Еще один вариант предыдущих ответов можно сохранить в исполняемом скрипте с именем my-ip-to:

#!/usr/bin/env python

import sys, socket

if len(sys.argv) > 1:
    for remote_host in sys.argv[1:]:
        # determine local host ip by outgoing test to another host
        # use port 9 (discard protocol - RFC 863) over UDP4
        with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
            s.connect((remote_host, 9))
            my_ip = s.getsockname()[0]
            print(my_ip, flush=True)
else:
    import platform

    my_name = platform.node()
    my_ip = socket.gethostbyname(my_name)
    print(my_ip)

он берет любое количество удаленных хостов и распечатывает локальные IP-адреса для доступа к ним один за другим:

$ my-ip-to z.cn g.cn localhost
192.168.11.102
192.168.11.102
127.0.0.1
$

И выведите лучший вариант, если не указан аргумент.

$ my-ip-to
192.168.11.102

Для linux env прочтите / proc / net / tcp, второй (локальный адрес) и третий (удаленный адрес) дадут IP-адреса в шестнадцатеричном формате.

Совет: если второй столбец обнулен (00000000: 0000), значит, это порт прослушивания :)

https://github.com/romol0s/python/blob/master/general/functions/getTcpListenIpsByPort.py

https://www.kernel.org/doc/Documentation/networking/proc_net_tcp.txt

Для Linux вы можете просто использовать check_output из системной команды hostname -I следующим образом:

from subprocess import check_output
check_output(['hostname', '-I'])

для гуглеров, я знаю, что вопрос был о кроссплатформенном решении

Kasper Skytte Andersen 25.07.2019 10:37

pyroute2 - отличная библиотека, с помощью которой можно получить не только IP-адреса, но также информацию о шлюзе и другую полезную информацию. Следующий код может получить IPv4-адрес любого интерфейса.

from pyroute2 import IPRoute
ip = IPRoute()

def get_ipv4_address(intf):
    return dict(ip.get_addr(label=intf)[0]['attrs'])['IFA_LOCAL']

print(get_ipv4_address('eth0'))

Решение для Windows, возьми или оставь.

получает только собственный IP-адрес текущего активного wlan [беспроводная локальная сеть], то есть IP-адрес компьютера (маршрутизатор Wi-Fi или сетевой коммутатор).

примечание: это не общедоступный IP-адрес устройства и не включает никаких внешних запросов, пакетов или общедоступных API.

Основная идея - проанализировать вывод shell command: ipconfig или ifconfig в Linux. мы используем подпроцесс для получения вывода.

def wlan_ip():
    import subprocess
    result=subprocess.run('ipconfig',stdout=subprocess.PIPE,text=True).stdout.lower()
    scan=0
    for i in result.split('\n'):
        if 'wireless' in i: #use "wireless" or wireless adapters and "ethernet" for wired connections
            scan=1
        if scan:
            if 'ipv4' in i:
                return i.split(':')[1].strip()
print(wlan_ip())

вот что происходит после CMD: 'ipconfig':

мы получаем этот вывод, мы захватили его в python, используя вывод подпроцесса.

C:\Users\dell>ipconfig

Wireless LAN adapter Wi-Fi:

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::f485:4a6a:e7d5:1b1c%4
   IPv4 Address. . . . . . . . . . . : 192.168.0.131
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Default Gateway . . . . . . . . . : 192.168.0.1

и мы проанализировали строку в python таким образом, чтобы выбрать ip беспроводного адаптера в текущей сети.

Похоже, этот код можно упростить, удалив флаговую переменную scan и заменив три оператора if только одним: if 'wireless' in i and 'ipv4' in i:

Georgy 03.12.2020 20:47

@Georgy нет, потому что нас интересует строка, содержащая ipv4, после нахождения первого активного беспроводного адаптера на нашем компьютере. не содержащие одновременно 'wireless' and 'ipv4'. вы пробовали кстати? Я пробовал ваш, и результат был None.

nikhil swami 04.12.2020 15:29

Это не чистое решение Python, как просил OP.

Chris Wolf 04.02.2021 17:20

@ChrisWolf сетевой код написан на C или C++ для большинства ОС. поэтому нет реального решения для доступа к сетевой информации через чистый Python. мы можем использовать только оболочку / ядро ​​соответствующих операционных систем для взаимодействия.

nikhil swami 05.02.2021 05:48

@nikhilswami Когда я сказал «чистый Python», я должен был сказать «чистый cPython». Дело в том, что выполнение таких трюков, как вызов внешних исполняемых файлов через подпроцесс, не является «чистым cPython» решением.

Chris Wolf 10.02.2021 02:31

Другие вопросы по теме