Как я могу найти локальные IP-адреса (например, 192.168.x.x или 10.0.x.x) на платформе Python независимо и с использованием только стандартной библиотеки?
используйте ifconfig -a и используйте вывод оттуда ...
@ Фредрик Это плохая идея. Прежде всего, вы без необходимости создаете новый процесс, и это может помешать вашей программе работать в жестко заблокированных конфигурациях (или вам придется разрешить права, которые вашей программе не нужны). Во-вторых, вы познакомитесь с ошибками для пользователей из разных стран. В-третьих, если вы вообще решаете запустить новую программу, вы не должны запускать устаревшую - ip addr гораздо более подходит (и его легче разбирать, загружать).
@phihag ты абсолютно прав, спасибо что поправили мою глупость
Более фундаментальная проблема здесь заключается в том, что в правильно написанной современной сетевой программе правильный (набор) локальных IP-адресов зависит от однорангового узла или набора потенциальных одноранговых узлов. Если локальный IP-адрес необходим для bind сокета для определенного интерфейса, то это вопрос политики. Если локальный IP-адрес необходим для передачи его одноранговому узлу, чтобы одноранговый узел мог «перезвонить», то есть для открытия соединения обратно с локальной машиной, тогда ситуация зависит от наличия NAT (трансляции сетевых адресов). коробки между ними. Если нет NAT, getsockname - хороший выбор.






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-адреса, используя этот метод.
Вариант: socket.gethostbyname (socket.getfqdn ())
Похоже, что это возвращает только один IP-адрес. Что делать, если у машины несколько адресов?
В Ubuntu по какой-то причине возвращается 127.0.1.1.
@Reinis I: в Ubuntu это возвращает 127.0.1.1 из-за строки в / etc / hosts. Эту линию можно удалить без страшных последствий.
Не полагайтесь на DNS (и, возможно, вызывайте блокировку сетевого ввода-вывода), если все, что вам нужно знать, - это локальное имя хоста.
@amarillion Я обнаружил, что rabbitmq недоволен, если эта строка отсутствует в / etc / hosts
@amarillion: В некоторых системах Ubuntu [какие?] пользователь может потерять возможность запускать команды sudo, если 127.0.1.1 отсутствует в файле hosts. У меня такое случалось, и это задокументировано.
@UnkwnTech, пожалуйста, не принимайте ответ, это явно ненадежно.
@ Джейсон Р. Кумбс, используйте следующий код для получения списка адресов IPv4, принадлежащих хост-машине: socket.gethostbyname_ex(socket.gethostname())[-1]
Этот работает, если вы знаете интерфейс: stackoverflow.com/a/24196955/385482
Это может быть проблемой и в Windows, потому что у меня есть VirtualBox, который устанавливает собственный сетевой адаптер. Команда socket.gethostbyname(socket.gethostname()) вернула адрес Virtualbox. Ответ @ JasonR.Coombs был полезен, потому что он вернул оба. VirtualBox первый на моем, но я не знаю, как он решает порядок
Ой. Понятия не имею, почему этот ответ был принят. Пожалуйста, люди, просто используйте уловку «подключитесь к 8.8.8.8 и получите локальный адрес этого сокета». По крайней мере, это гарантированно работает.
он работает, только если есть один сетевой интерфейс, если у вас несколько, например Ethernet и беспроводной, он показывает неправильный IP-адрес при подключении к беспроводной сети. используйте другие ответы, которые используют метод getsockname (), чтобы получить правильный IP-адрес
Очень мило, вы спасаете жизнь !! : D
В Ubuntu 17.10 даже ответ @ gimel возвращает "127.0.0.1"
Каждое использование socket.getfqdn() приводит к задержке на моей платформе в 8-10 секунд. (Я использую Windows в большой корпоративной сети.)
вернуть '127.0.0.1'
Например, это не возвращает адреса VPN.
У меня есть опция, которая может отфильтровывать IPv6 и локальные адреса обратной связи / ссылки, а также проверять, является ли вывод действительным IP. stackoverflow.com/questions/24196932/…
Я использую AWS EC2, и мне пришлось использовать модификацию ответа @Barmaley: socket.gethostbyname_ex(socket.gethostname())[-1][-1]
Боюсь, что нет хороших независимых от платформы способов сделать это, кроме подключения к другому компьютеру и отправки ему вашего 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
Было бы неплохо перехватить исключения socket.error, которые могут быть вызваны s.connect ()!
Хорошо, я все равно хочу, чтобы IP-адрес видел какой-то клиент при подключении к моей службе.
Лучше использовать IP-адрес вместо доменного имени - он должен быть быстрее и не зависеть от доступности DNS. Например. мы можем использовать 8.8.8.8 IP - публичный DNS-сервер Google.
Очень умно, отлично работает. Вместо gmail или 8.8.8.8 вы также можете использовать IP или адрес сервера, с которого вы хотите, чтобы вас видели, если это применимо.
@ Проф. Фалькен Ага! Он отлично работает и в локальной сети. Вы можете подключиться практически к любой машине, прослушивающей указанный порт. Мне нужно было использовать IP-адрес сервера в качестве ключа для набора Redis, поэтому я просто использовал сервер и порт Redis для получения IP-адреса, и это сработало как шарм! :-)
как заставить это работать с широковещательными адресами вместо gmail.com?
Мне это нравится. Мне бы лучше, если бы я мог выяснить, как использовать IP-адрес туннеля vpn.
человек, использование подключения к сокету UDP ничего не дает. Но он дает сокету общедоступный IP-адрес. Я использовал s.connect (("123.123.123.123", 80))
В этом примере есть внешняя зависимость от возможности фактического разрешения gmail.com. Если вы установите для него IP-адрес, который не находится в вашей локальной сети (не имеет значения, работает он или нет), он будет работать без зависимостей и без сетевого трафика.
Как отметил @grim, было бы лучше открыть сокет с наиболее вероятным доступным компьютером, поскольку многие сетевые устройства не имеют бесплатного доступа к Интернету. Я думаю, что ваш шлюз или DHCP-сервер могут быть лучшими. Вы можете получить свой шлюз в Linux с помощью stackoverflow.com/a/6556951/1411638
@feisky Я только что подтвердил, что это также работает на OSX (под управлением El Capitan)
Умно, таким образом можно найти правильный IP-адрес интерфейса для указанного хоста назначения и без фактической отправки какого-либо пакета.
Чтобы добавить к комментариям за 9 лет: это решение просто работало для меня на автономном процессоре под управлением Yocto Linux в 2017 году.
Это решение работает, но я предпочитаю не использовать IP-адрес Google (8.8.8.8), а, как указал Джеймисон Беккер, например, s.connect(('10.255.255.255', 1)).
Сокеты SOCK_DGRAM (UDP) не поддерживают connect. Поэтому вам следует придерживаться какого-то TCP-адреса
Как я предлагал в отвечать за 3 года до последнего обновления, вы можете заменить конкретное имя порта на s.connect (('<broadcast>', 0)), но сначала вам нужно вызвать s.setsockopt (socket.SOL_SOCKET , socket.SO_BROADCAST, 1)
@yanpas "Сокеты SOCK_DGRAM (UDP) не поддерживают соединение. Поэтому вам следует придерживаться какого-то TCP-адреса". Не правда
Использование '<broadcast>' имеет преимущества: (а) отсутствие необходимости подключения к Интернету и (б) отсутствие необходимости знать какие-либо номера портов в локальной сети.
Это самое умное решение, которое я когда-либо видел, и, судя по комментариям, прошедшими испытания на протяжении многих лет, оно кажется проверенным. Чтобы еще больше отполировать его, я предлагаю использовать порт 53 с udp для сервера имен, например 8.8.8.8, и порт 9 (протокол сброса rfc 863) с udp / tcp для произвольных хостов других типов.
В моей книге хакерство не означает, что что-то плохо, если оно работает хорошо и все еще может быть понято.
На самом деле для этого вообще не требуется доступ в Интернет, только подключение к сети. Он просто попытается найти 8.8.8.8. Может кто-нибудь это подтвердить? если да, то можно было бы отредактировать ответ
Очень полезно, особенно когда установлен net-tools, но по какой-то загадочной причине не может работать ifconfig. Вы можете узнать свой локальный IP-адрес с помощью всего нескольких строк кода. Python просто потрясающий.
Вы можете использовать модуль 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.
Как указано в вопросе, я хочу что-то от установки по умолчанию, так как дополнительных установок не требуется.
@MattJoiner Ни то, ни другое уже не соответствует действительности (последняя версия имеет двоичные файлы Windows на PyPI и поддерживает Py3K).
@ Jean-PaulCalderone FWIW, последняя версия netifaces делает поддерживает IPv6 в Windows.
этот модуль должен быть частью стандартной библиотеки, учитывая, что python утверждает философию `` батарейки включены ''
поднять ошибку, может быть, он будет включен в sys, кажется, хороший кандидат для этого.
@MattJoiner - обратите внимание, что в Ubuntu последняя версия не требует компилятора C ни для python, ни для Py3K. И для модуля тоже есть пакеты.
Если вы не хотите использовать внешние пакеты и не хотите полагаться на внешние серверы Интернета, это может помочь. Это образец кода, который я нашел на 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.
+1 Эта техника как минимум пытается вернуть все адреса на машине.
Этот сценарий не работает на моей машине после возврата первого адреса. Ошибка: «AttributeError: объект 'LP_IP_ADDR_STRING' не имеет атрибута 'ipAddress'». Я подозреваю, что это как-то связано с IPv6-адресом.
Оказывается, проблема в том, что для чего-либо, кроме первого IP-адреса, adNode не разыменовывается. Добавьте еще одну строчку в пример в цикле while, и она у меня сработает: adNode = adNode.contents
Как псевдоним 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, правильным способом является использование модуля 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])
Версия, которая также будет работать в локальных сетях без подключения к Интернету:
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.
Забыл отметить, что код в моем комментарии выше (не может больше редактировать) также дает мне IP-адреса VPN, что было важно для меня, когда я пришел сюда в поисках ответа.
Странно, я не получаю IP-адреса VPN. (Это то, к чему я также пытаюсь получить доступ) Вышеупомянутое дает мне мой стандартный внутренний IP-адрес, но не IP-адрес для VPN, к которой я также подключен
kdbdallas, я не знаю, используете ли вы win / osx или Linux, но я думаю, что в этом контексте VPN-соединения обычно отображаются как отдельное сетевое устройство.
К сожалению, это не вернет адреса IPv6 - похоже, для этого вам понадобится socket.getaddrinfo(). Другими словами, ответ Накилона ниже даст вам лучшие результаты.
@ Владимир Палант, я уже упоминал об этом. Кроме того, его реализация может возвращать повторяющиеся IP-адреса. Он также не упоминает, работает ли он в Windows, OSX и Linux или нет.
@Alexander: Просто хочу сказать, что этот ответ гораздо менее полезен, чем раньше (и это не похоже на то, чтобы фильтровать дубликаты - это большое дело;). Согласно документации socket.getaddrinfo() должен стабильно работать на разных платформах, но я проверял его только на Linux, не беспокоился о других операционных системах.
@Alexander, /etc/resolve.conf: No such file or directory и у меня есть локальный IPv4-адрес, показанный ifconfig.
Я могу подтвердить, что обновленная версия работает с Ubuntu 14.04 как с Python2, так и с Py3k.
«Обновление» демонстрирует хороший трюк с connect () на UDP-сокете. Он не отправляет трафик, но позволяет найти адрес отправителя для пакетов указанному получателю. Порт скорее всего не имеет значения (даже 0 должен работать). На многосетевом хосте важно выбрать адрес в правильной подсети.
Вроде не могу подключиться к 8.8.8.8 по 80 порту - у кого-нибудь еще есть такая проблема? google.com с другой стороны работает нормально
Крис, это сработает, если вы попробуете вместо этого использовать порт 53?
Я нашел этот ответ полезным и в конечном итоге использовал socket.gethostbyname_ex(socket.gethostname())[2], который работает для моих нужд, это двухуровневый Arch Linux и python2 / 3. Я не уверен, что мне не хватает, потому что я не использовал весь фрагмент, указанный в ответе.
Я предполагаю, что вам будет не хватать только псевдонима в вашей конфигурации оболочки (который вы разделяете среди систем, к которым у вас есть доступ, независимо от ОС, я полагаю), который будет работать на всех из них при обычных обстоятельствах.
Комбинированный код псевдонима инициирует ненужное внешнее соединение с 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]]
просто потому, что вы можете написать этот код в одной строке, это не значит, что вы должны ...
@JackLeo Он работает как псевдоним в командной строке. Если вы хотите сделать это правильно, вам следует в первую очередь использовать модуль Python, который правильно обрабатывает IPv6 и несколько сетевых интерфейсов.
Было бы намного лучше, если бы у вас была не-одинарная версия. Я хочу использовать это в скрипте Python, а не в соревнованиях по гольфу.
Правильный способ - использовать модуль Python с поддержкой IPv6, а не какие-либо ответы на этой странице.
Я думаю, что однострочник - это круто - конечно, вы можете очистить его для реального использования. Он работает на AWS EC2 под управлением AMI на базе CentOS, спасибо.
Я использую следующий модуль:
#!/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.
Я использовал python 3.4, и часть 'struct.pack (...)' нужно было изменить на 'struct.pack (' 256s ', bytes (ifname [: 15],' utf-8 '))'. См. Этот вопрос: stackoverflow.com/q/27391167/76010
на Raspbian с Python 2.7.3 - bytes () не понравился второй аргумент. Но это сработало: struct.pack('256s', bytes(ifname[:15]))
К вашему сведению, я могу проверить, что метод:
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'
Поэтому вы должны использовать "/ sbin / ifconfig", как сказал Гавалет. Он также работает в Red Hat 4.1.2-48.
Устарело с версии 2.6. Используйте модуль подпроцесса для выполнения команд.
И ifconfig также устарел. Используйте iproute2.
Получите все IP-адреса: import sh; [ip.split () [1] [5:] для ip в фильтре (лямбда x: 'inet addr' в x, sh.ifconfig (). split ("\ n"))]
это дает мне localhost 127.0.0.1 ip на raspbian
Как мы узнаем, что выходной формат ipconfig никогда не меняется?
потому что это устарело!
Чтобы получить список 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 (т.е. бесполезно).
имя хоста -I (с большой буквы) недоступно в старых версиях различных операционных систем. Например, CentOS 5.2. Итак, я полагаю, что приведенный выше сценарий следует предпочесть на всякий случай. PS: Спасибо за комментарий. Команда полезна для последних версий ОС.
Следует отметить, что использование имени хоста, предложенное Робом, специфично для Linux. Например, Solaris с радостью изменит ваше имя хоста на "-I", если вы вызовете команду, заданную как root.
Спасибо за эту заметку @EliHeady, которая спасла миллионы жизней: D
Один простой способ произвести "чистый" вывод с помощью утилит командной строки:
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, чтобы увидеть все адреса.
Это чертовски много оболочки для вопроса о стандартной библиотеке ... Кроме того, синтаксический анализ ifconfig не является переносимым и даже не будет надежно работать на одной машине.
У машины может быть несколько сетевых интерфейсов (включая локальный шлейф 127.0.0.1), о котором вы упомянули. Что касается ОС, то это еще и «настоящий IP-адрес».
Если вы хотите отслеживать все интерфейсы, взгляните на следующий пакет Puthon: http://alastairs-place.net/netifaces/
Я думаю, вы можете избежать того, чтобы gethostbyname возвращал 127.0.0.1, если вы опустите запись обратной связи из файла hosts. (подлежит проверке).
как получить этот модуль netifaces?
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 или внутренней сети, что явно не то, что ему нужно.
Метод Socket API
см. https://stackoverflow.com/a/28950776/711085
Минусы:
Рефлекторный метод
(Обратите внимание, что это не отвечает на вопрос 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)
Преимущества:
Недостатки (и обходные пути):
редактировать: Хотя изначально я думал, что эти методы действительно плохие (если вы не используете много резервных вариантов, код может быть неактуальным через много лет), все же возникает вопрос «что такое Интернет?». Компьютер может иметь множество интерфейсов, указывающих на множество различных сетей. Более подробное описание темы погуглите по gateways and routes. Компьютер может иметь доступ к внутренней сети через внутренний шлюз или к всемирной паутине через шлюз, например, на маршрутизаторе (обычно так). Локальный IP-адрес, о котором спрашивает OP, четко определен только для одного канального уровня, поэтому вы должны указать это («это сетевая карта или кабель Ethernet, о котором мы говорим?») . На поставленный вопрос может быть несколько неуникальных ответов. Однако глобальный IP-адрес во всемирной паутине, вероятно, четко определен (при отсутствии массивной фрагментации сети): вероятно, обратный путь через шлюз, который может получить доступ к TLD.
Это вернет ваш адрес в локальной сети, если вы находитесь за NAT. Если вы подключаетесь к Интернету, вы можете подключиться к веб-службе, которая возвращает один из ваших общедоступных IP-адресов.
Он не создает TCP-соединение, потому что он создает UDP-соединение.
В качестве альтернативы в версии API сокетов замените s.connect (('INSERT SOME TARGET WEBSITE.com', 0)) на s.setsockopt (socket.SOL_SOCKET, socket.SO_BROADCAST, 1); s.connect (('< broadcast> ', 0)), чтобы избежать поиска в DNS. (Думаю, может быть проблема с трансляцией, если есть брандмауэр)
В 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-адрес?
Сокет открывается, чтобы получить fd для связи с ядром (через ioctl). Сокет не привязан к интерфейсу, для которого вы хотите получить информацию об адресе - это просто механизм связи между пользовательским пространством и ядром. en.wikipedia.org/wiki/Ioctllxr.free-electrons.com/source/net/socket.c
Работает на Python3 с одной модификацией: struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14) следует заменить на struct.pack('16sH14s', iface.encode('utf-8'), socket.AF_INET, b'\x00'*14).
как я могу сделать то же самое для ipv6?
@ChristianFischer ioctl - это устаревший интерфейс, который, по моему мнению, не поддерживает IPv6 и, скорее всего, никогда не будет. Я думаю, что «правильный» путь - через Netlink, что не очень просто в Python. Я думаю, что libc должна иметь функцию getifaddrs, к которой можно получить доступ через модуль pythons ctypes, который может работать - man7.org/linux/man-pages/man3/getifaddrs.3.html
@Maddy ioctl - это устаревший интерфейс, который, по моему мнению, не поддерживает IPv6 и, скорее всего, никогда не будет. Я думаю, что «правильный» путь - через Netlink, что не очень просто в Python. Я думаю, что libc должна иметь функцию getifaddrs, к которой можно получить доступ через модуль pythons ctypes, который может работать - man7.org/linux/man-pages/man3/getifaddrs.3.html
Это хорошо, потому что не требует подключения к Интернету.
Хорошо, так что это специфично для 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())
Вместо того, чтобы просто публиковать блок кода, пожалуйста, объяснять, почему этот код решает поставленную проблему. Без объяснения причин это не ответ.
В принятом ответе уже упоминается об этом, и вы даже не пытались дать более подробную информацию об этом.
Этот ответ - моя личная попытка решить проблему получения 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".
import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]
Хм ... на сервере с двумя сетевыми адаптерами это дает один назначенных IP-адресов, но повторяется три раза. На моем ноутбуке выдает 127.0.1.1 (повторяется три раза ...) ...
Дает мне ['fe80::34e8:fe19:1459:2cde%22','fe80::d528:99fb:d572:e289%12', '192.168.56.1', '192.168.1.2'] на рабочем столе Windows.
Примечание: это не использование стандартной библиотеки, но довольно простое.
$ pip install pif
from pif import get_public_ip
get_public_ip()
вопросы касались поиска IP с помощью stdlib
Что ж, вы можете использовать команду «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)
никогда не делал. всего два цента
не работает, как упоминалось выше на ubuntu
Это вариант ответа 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
@JamieLindsey У вас есть какие-нибудь подробности о вашей ОС и конфигурации сети? Кроме того, что возвращает что-то вроде get_local_addr(remove = "www.google.com")? Регистрация socket.error, сгенерированного _get_local_addr (), может помочь в диагностике.
Вариант ответа ниндзягеко. Это должно работать в любой локальной сети, которая разрешает широковещательную передачу 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> - действительное имя хоста? !! Сколько из этих словесных имен хостов допустимы?
Это работает для меня на Ubuntu 20.04 - получение 192.168.0.24, а не 127.0.0.1
Работает на всех системах, на которых я его тестировал. Windows, Android, Linux, Mac.
Когда я использую <broadcast> в Windows 10, я получаю IP-адрес беспроводной сетевой карты. Когда я использую 10.255.255.255, я получаю IP-адрес адаптера Ethernet TAP. Оба действительны. Но результаты разные, лол.
netifaces доступен через pip и easy_install. (Я знаю, его нет в базе, но, возможно, стоит установить.)
У netifaces есть некоторые странности на разных платформах:
Вот код для 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 действительно значительно облегчает жизнь при решении этой проблемы.
На 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]
В python 3 вам нужно заменить «команды» на «подпроцесс», остальное то же самое.
Если у компьютера есть маршрут к Интернету, всегда будет работать для получения предпочтительного локального 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-сервером?
Версия, которая, как мне кажется, еще не была опубликована. Я тестировал 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'
Этот метод возвращает «основной» IP-адрес в локальном поле (тот, у которого есть маршрут по умолчанию)..
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!
Блестяще. Работает на Win7,8,8.1 + Linux Mint & Arch, включая виртуальные машины.
Работает в Windows 10 Pro! Спасибо, Джеймисон Беккер!
По какой-то причине это не работает в 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.
Это должен быть принятый ответ. socket.gethostbyname(socket.gethostname()) дает ужасные результаты.
Mac OSX 10.14.3 (18D109) возвращает 127.0.0.1 в качестве основного IP-адреса, если нет маршрута к Интернету, но маршрутизатор назначает IP-адрес локальной сети через DHCP. По-прежнему может быть назначен 192.168.1.x, который будет действительным и, вероятно, предпочтительным адресом LAN.
@RichAndrews Эта ситуация обсуждается в ответе: «Это возвращает единственный IP-адрес, который является основным (с маршрутом по умолчанию)». 127.0.0.1 будет ожидаемым ответом, если у вас нет маршрута в Интернет.
Будет ли это работать с любым IP-адресом частная сеть? Например. 10.0.0.0 у меня тоже работает.
Работает с AMI на базе AWS EC2. На MacOS-10.14, подключенном к корпоративной VPN, возвращает IP-адрес с интерфейса utun1 (предположим, что это VPN-IP)
Это не очень похоже на 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) могут показывать.
Я решил использовать службу и / или 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 не входит в стандартную библиотеку.
import socket
print(socket.gethostbyname(socket.getfqdn()))
Разница, которую вы опубликовали, сбивает с толку, поскольку она не имеет ничего общего с какой-либо IDE. Это интерактивная оболочка Python против сценария.
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 не является частью стандартной библиотеки, и очень похожий ответ уже был опубликован.
Если вы ищете 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'])
для гуглеров, я знаю, что вопрос был о кроссплатформенном решении
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'))
получает только собственный 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())
мы получаем этот вывод, мы захватили его в 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 нет, потому что нас интересует строка, содержащая ipv4, после нахождения первого активного беспроводного адаптера на нашем компьютере. не содержащие одновременно 'wireless' and 'ipv4'. вы пробовали кстати? Я пробовал ваш, и результат был None.
Это не чистое решение Python, как просил OP.
@ChrisWolf сетевой код написан на C или C++ для большинства ОС. поэтому нет реального решения для доступа к сетевой информации через чистый Python. мы можем использовать только оболочку / ядро соответствующих операционных систем для взаимодействия.
@nikhilswami Когда я сказал «чистый Python», я должен был сказать «чистый cPython». Дело в том, что выполнение таких трюков, как вызов внешних исполняемых файлов через подпроцесс, не является «чистым cPython» решением.
Локальный IP? Или публичный IP? Как вы собираетесь работать с системами с несколькими IP-адресами?