Python'un stdlib'ini kullanarak yerel IP adreslerini bulma


547

Yerel IP adreslerini (yani 192.168.xx veya 10.0.xx) Python platformunda bağımsız olarak ve yalnızca standart kitaplığı kullanarak nasıl bulabilirim?


7
Yerel IP? Veya genel IP? Birden fazla IP'ye sahip sistemlerle nasıl başa çıkacaksınız?
Sargun Dhillon

ifconfig -açıktıyı oradan kullanın ve kullanın ...
Fredrik Pihl

16
@Fredrik Bu kötü bir fikir. Her şeyden önce, gereksiz yere yeni bir işlem istemiş olursunuz ve bu da programınızın sıkıca kilitlenmiş yapılandırmalarda çalışmasını engelleyebilir (veya programınızın ihtiyaç duymadığı haklara izin vermeniz gerekir). İkinci olarak, farklı yerel ayarların kullanıcıları için hatalar tanıtacaksınız. Üçüncü olarak, eğer sen hiç yeni bir program başlatmak için karar, bir kaldırılmış bir başlangıç olmamalıdır - ip addr(boot ve daha kolay ayrıştırma kadar) çok daha uygundur.
phihag

12
@phihag kesinlikle haklısın, aptallığımı düzelttiğin için teşekkürler
Fredrik Pihl

1
Burada daha temel bir sorun, düzgün yazılmış modern bir ağ programında, yerel IP adres (ler) inin akranına veya potansiyel eş grubuna bağlı olmasıdır. Yerel IP adresi bindbelirli bir arabirimin soketine ihtiyaç duyuyorsa, bu bir ilke sorunudur. Eşin "geri çağırabilmesi", yani yerel makineyle bağlantıyı yeniden açabilmesi için bir eşe teslim etmek için yerel IP adresi gerekiyorsa, durum herhangi bir NAT (Ağ Adresi Çevirisi) olup olmadığına bağlıdır. aradaki kutular. NAT yoksa, getsocknameiyi bir seçimdir.
Pekka Nikander

Yanıtlar:


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

Bu her zaman işe yaramaz ( 127.0.0.1ana bilgisayar adı /etc/hostsas olan makinelerde geri döner 127.0.0.1), bir palimat, gimel'in gösterdiği şeydir, socket.getfqdn()bunun yerine kullanın. Elbette makinenizin çözümlenebilir bir ana makine adına ihtiyacı vardır.


43
Bunun platformdan bağımsız bir çözüm olmadığını belirtmek gerekir. Birçok Linux bu yöntemi kullanarak 127.0.0.1 IP adresiniz olarak dönecektir.
Jason Baker

20
Bir varyasyon: socket.gethostbyname (socket.getfqdn ())
gimel

55
Bu, yalnızca tek bir IP adresi döndürüyor gibi görünüyor. Makinenin birden fazla adresi varsa ne olur?
Jason R.Combs

26
Ubuntu'da bu bir nedenle 127.0.1.1 değerini döndürür.
Mart'ta 5

13
@Jason R. Coombs, ana makineye ait IPv4 adreslerinin listesini almak için aşağıdaki kodu kullanın:socket.gethostbyname_ex(socket.gethostname())[-1]
Barmaley

460

Ben sadece buldum ama biraz acayip görünüyor, ancak dediler ki * nix üzerinde denedim ve pencerelerde yaptım ve çalıştı.

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

Bu, internet erişiminiz olduğunu ve yerel proxy olmadığını varsayar.


31
Makinede birkaç arabiriminiz varsa ve örneğin gmail.com
elzapp 20:10

4
S.connect () ile yükselen socket.error istisnalarını yakalamak iyi bir fikir olabilir!
phobie

39
Etki alanı adı yerine IP adresi kullanmak daha iyi olur - DNS kullanılabilirliğinden daha hızlı ve bağımsız olmalıdır. Örneğin, Google'ın genel DNS sunucusu olan 8.8.8.8 IP'yi kullanabiliriz.
wobmene

10
Çok zeki, mükemmel çalışıyor. Gmail veya 8.8.8.8 yerine, uygunsa, görülmesini istediğiniz sunucunun IP'sini veya adresini de kullanabilirsiniz.
Prof. Falken sözleşmesi

3
Bu örnek, gmail.com'u gerçekten çözümleyebilmenin dışsal bağımlılığına sahiptir. Yerel LAN'ınızda olmayan bir IP adresine ayarlarsanız (yukarı veya aşağı olup olmadığı önemli değildir), bağımlılıklar olmadan ve ağ trafiği olmadan çalışır.
gaddar

254

Bu yöntem, yerel kutudaki (birincil yolu olan) "birincil" IP değerini döndürür .

  • Yönlendirilebilir ağ erişimine veya herhangi bir bağlantıya İHTİYAÇ YOKTUR.
  • Tüm arabirimler ağdan çıkarılmış olsa bile çalışır.
  • Başka bir yere ihtiyaç duymaz, hatta almaya çalışmaz .
  • NAT, genel, özel, harici ve dahili IP'lerle çalışır
  • Harici bağımlılığı olmayan saf Python 2 (veya 3).
  • Linux, Windows ve OSX üzerinde çalışır.

Python 3 veya 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

Bu, birincil olan (varsayılan yolu olan) tek bir IP döndürür. Bunun yerine tüm arabirimlere (localhost, vb. Dahil) bağlı tüm IP'lere ihtiyacınız varsa, bu yanıta bakın .

Evde wifi kutunuz gibi bir NAT güvenlik duvarının arkasındaysanız, bu, genel NAT IP'nizi değil, yerel WIFI yönlendiricinize varsayılan bir rotaya sahip olan yerel ağdaki özel IP'nizi gösterecektir; wifi yönlendiricinizin harici IP'sini almak için bu kutuda çalıştırılması veya IP'yi geri yansıtabilecek whatismyip.com/whatismyipaddress.com gibi harici bir hizmete bağlanmanız gerekir ... ancak bu orijinal sorudan tamamen farklıdır. :)


7
Raspbian'da Python 2 ve 3 ile çalışır!
pierce.jason

3
Parlak. VM'ler dahil Win7,8,8.1 + Linux Mint & Arch üzerinde çalışır.
shermy

2
Windows 10 Pro'da çalışır! Teşekkürler Jamieson Becker!
varantes

3
Bazı nedenlerden dolayı bu Mac OS X El Capitan 10.11.6 üzerinde çalışmaz (bir istisna işletim sistemi hatası oluşturur: [Errno 49] İstenen adres atanamıyor). Bağlantı noktasını '0'dan' 1'e değiştirmek: s.connect (('10.255.255.255', 1)) hem Mac OS X hem de Linux Ubuntu 17.04
Pedro Scarapicchia Junior

10
Bu kabul edilen cevap olmalı. socket.gethostbyname(socket.gethostname())korkunç sonuçlar verir.
Jason Floyd

142

Bir takma ad olarak myip, bu her yerde çalışması gerekir:

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])'"
  • Geçerli IPv4 adresini bulmak için Python 2.x, Python 3.x, modern ve eski Linux dağıtımları, OSX / macOS ve Windows ile doğru şekilde çalışır.
  • Birden fazla IP adresi, IPv6, yapılandırılmış IP adresi veya internet erişimi olmayan makineler için doğru sonucu döndürmez.

Yukarıdaki ile aynı, ancak sadece Python kodu:

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])
  • Hiçbir IP adresi yapılandırılmamışsa bu bir istisna atar.

İnternet bağlantısı olmayan LAN'larda da çalışacak sürüm:

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

(teşekkürler @ccpizza )


Arkaplan :

Kullanmak socket.gethostbyname(socket.gethostname())burada işe yaramadı, çünkü bulunduğum bilgisayarlardan birinde /etc/hostsyinelenen girişler ve kendisine referanslar vardı . socket.gethostbyname()yalnızca içindeki son girişi döndürür /etc/hosts.

Bu başlayarak tüm adreslere eler benim ilk girişimi oldu "127.":

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

Bu, Linux ve Windows üzerinde Python 2 ve 3 ile çalışır, ancak birkaç ağ cihazı veya IPv6 ile ilgilenmez. Ancak, son Linux dağıtımları üzerinde çalışmayı bıraktı, bu yüzden bunun yerine bu alternatif tekniği denedim. Hiç de Google DNS sunucusuna bağlanmaya çalışır 8.8.8.8limanında 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])

Daha sonra yukarıdaki iki tekniği, her yerde çalışması gereken tek bir myipastarda birleştirdim ve bu cevabın üstünde takma ad ve Python snippet'i oluşturdum .

IPv6'nın artan popülaritesi ve birden çok ağ arayüzüne sahip sunucular için, IP adresini bulmak için üçüncü taraf bir Python modülü kullanmak, muhtemelen burada listelenen yöntemlerden daha sağlam ve güvenilirdir.


2
@Alexander: Bu cevabın eskisinden çok daha az kullanışlı olduğunu söylemek (ve kopyaları filtrelemek gibi bir şey değil;). Belgelere göre socket.getaddrinfo()platformlar arasında tutarlı bir şekilde çalışmalı - ancak sadece Linux'ta kontrol ettim, diğer işletim sistemleri hakkında rahatsız etmedim.
Wladimir Palant

1
@Alexander /etc/resolve.conf: No such file or directoryve yerel IPv4 adresim tarafından gösteriliyor ifconfig.
anatoly techtonik

2
Güncellenmiş sürümün Python2 ve Py3k ile Ubuntu 14.04 ile çalıştığını doğrulayabilirim.
Uli Köhler

4
"Güncelleme", UDP soketinde connect () ile hoş bir numara gösterir. Hiçbir trafik göndermez, ancak belirtilen alıcıya paketler için gönderen adresinin ne olacağını bulmanızı sağlar. Liman muhtemelen ilgisizdir (0 bile çalışmalıdır). Çok evli bir ana bilgisayarda, doğru alt ağda bir adres seçmek önemlidir.
Peter Hansen

17
Bu kodu tek bir satıra
yazabildiğiniz için

91

Netifaces modülünü kullanabilirsiniz . Sadece yaz:

pip install netifaces

komut kablonuzda ve varsayılan Python yüklemesinde kendini kurar.

O zaman bu şekilde kullanabilirsiniz:

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

Bilgisayarımda yazdırıldı:

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

Bu modülün yazarı, Windows, UNIX ve Mac OS X üzerinde çalışması gerektiğini iddia ediyor.


20
Soruda belirtildiği gibi, varsayılan kurulumdan bir şey istiyorum, ek kurulum gerektirmediği gibi.
UnkwnTech

4
Netfaces, Windows'ta IPv6'yı desteklemediği ve bakımsız görünmesi dışında, bu benim en sevdiğim cevap olacaktır. Windows'da IPv6 adreslerini nasıl alacağınızı anlayan var mı?
Jean-Paul Calderone

3
netifaces py3k'yi desteklemez ve pencerelerde PITA olan bir C derleyicisi gerektirir.
Matt Joiner

4
@MattJoiner Bunların hiçbiri artık doğru değil (en son sürümde PyPI üzerinde Windows ikili dosyaları var ve Py3K desteği yok).
alastair

4
Jean-PaulCalderone FWIW @, netifaces son sürümü yapar Windows üzerinde destek IPv6.
alastair

47

Soket API yöntemi

bkz. https://stackoverflow.com/a/28950776/711085

Downsides:

  • Çapraz platform değil.
  • İnternette belirli adreslerin varlığına bağlı daha fazla yedek kod gerektirir
  • Bir NAT'ın arkasındaysanız bu da çalışmaz
  • Muhtemelen (genellikle ISS'lerin) DNS kullanılabilirliğinden bağımsız olmayan bir UDP bağlantısı oluşturur (8.8.8.8: Google'ın (tesadüfen DNS) sunucusu gibi fikirler için diğer yanıtlara bakın)
  • Kullanılmadığı garanti edilen sayısal bir IP adresi gibi hedef adresi KULLANILAMAZ duruma getirdiğinizden emin olun. Fakesubdomain.google.com veya somefakewebsite.com gibi bazı alanları KULLANMAYIN; o tarafa (şimdi veya gelecekte) hala spam gönderecek ve süreçte kendi ağ kutularınızı da spam yapacaksınız.

Reflektör yöntemi

(Bunun OP'nin yerel IP adresi sorusuna cevap vermediğini unutmayın, örneğin 192.168 ...; kullanım durumuna bağlı olarak daha arzu edilen genel IP adresinizi verir.)

Whatismyip.com gibi bir siteyi (ancak bir API ile) sorgulayabilirsiniz, örneğin:

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)

veya python2 kullanıyorsanız:

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)

Avantajları:

  • Bu yöntemin bir tarafı, platformlar arası
  • Çirkin NAT'ların arkasından çalışır (örneğin ev yönlendiriciniz).

Dezavantajları (ve geçici çözümleri):

  • Bu web sitesinin hazır olması, formatın değişmemesi (neredeyse kesinlikle değişmemesi) ve DNS sunucularınızın çalışmasını gerektirir. Arıza durumunda diğer üçüncü taraf IP adresi yansıtıcılarını da sorgulayarak bu sorunu hafifletebilirsiniz.
  • Birden fazla yansıtıcıyı sorgulamazsanız (güvenliği ihlal edilmiş bir yansıtıcının adresinizin olmadığını bir şey olduğunu söylemesini önlemek için) veya HTTPS kullanmıyorsanız (ortadaki bir adamın saldırısını taklit etmek için) sunucu olmak)

edit : Başlangıçta bu yöntemlerin gerçekten kötü olduğunu düşündüm (pek çok yedek kullanmadıkça, kod artık uzun yıllar ilgisiz olabilir), "internet nedir?" sorusunu ortaya çıkarır. Bir bilgisayarın birçok farklı ağa işaret eden birçok arayüzü olabilir. Konunun daha ayrıntılı bir açıklaması için google forgateways and routes. Bir bilgisayar bir dahili ağa dahili bir ağ geçidi üzerinden erişebilir veya dünya çapında ağa örneğin bir yönlendirici üzerindeki ağ geçidi üzerinden erişebilir (genellikle durum). OP'nin sorduğu yerel IP adresi yalnızca tek bir bağlantı katmanına göre iyi tanımlanmıştır, bu nedenle şunu belirtmelisiniz ("ağ kartı mı yoksa bahsettiğimiz ethernet kablosu mu?") . Bu soruya gösterildiği gibi benzersiz olmayan birden fazla cevap olabilir. Bununla birlikte, dünya çapındaki web üzerindeki küresel IP adresi muhtemelen iyi tanımlanmıştır (büyük ağ parçalanması olmadığında): muhtemelen TLD'lere erişebilen ağ geçidi üzerinden dönüş yolu.


Bir NAT'ın arkasındaysanız LAN genel adresinizi döndürür. İnternete bağlanıyorsanız, genel IP adreslerinizden birini döndüren bir web hizmetine bağlanabilirsiniz.
phihag

Bir UDP bağlantısı oluşturduğundan TCP bağlantısı oluşturmaz.
Anuj Gupta

2
Soket API sürümünde alternatif olarak, s.connect (('SOME TARGET WEBSITE.com', 0)) öğesini s.setsockopt (socket.SOL_SOCKET, socket.SO_BROADCAST, 1); s.connect (('< broadcast> ', 0)). (Bir güvenlik duvarı varsa bir yayın ile ilgili bir sorun olabilir sanırım)
dlm

45

Bilgisayarın Internet yolu varsa, / etc / hosts doğru ayarlanmamış olsa bile bu her zaman tercih edilen yerel ip adresini almak için çalışır.

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]

bu nasıl çalışıyor ? , 8.8.8.8bir google dns sunucusu yerel bir dns sunucusu ile yapabilir miyiz?
Ciasto piekarz

39

Linux'ta:

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

Yani bu etkili bir şey yapmaz bir soket açar ve yerel IP almak için o soket hakkında ham verileri kontrol?
Dave

1
Çekirdekle iletişim kurmak için soket açılır (üzerinden ioctl). Soket, addr hakkında bilgi istediğiniz arabirime bağlı değildir - sadece kullanıcı alanı ve çekirdek arasındaki bir iletişim mekanizmasıdır. en.wikipedia.org/wiki/Ioctl lxr.free-electrons.com/source/net/socket.c
tMC

2
Tek bir değişiklikle Python3 üzerinde çalışır: struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)değiştirilmelidirstruct.pack('16sH14s', iface.encode('utf-8'), socket.AF_INET, b'\x00'*14)
pepoluan

1
@ChristianFischer ioctl, IPv6'yı desteklediğine ve muhtemelen asla olmayacağına inanmadığım eski bir arayüz. 'Doğru' yolun Python'da çok basit olmayan Netlink üzerinden olduğunu düşünüyorum. Bence libc, pythons modülü getifaddrsüzerinden erişilebilen bir işleve sahip olmalı ctypes- man7.org/linux/man-pages/man3/getifaddrs.3.html
tMC

1
@Maddy ioctl, IPv6'yı desteklediğine inanmıyorum ve muhtemelen asla olmayacak eski bir arayüz. 'Doğru' yolun Python'da çok basit olmayan Netlink üzerinden olduğunu düşünüyorum. Bence libc, pythons ctypes modülü üzerinden erişilebilen getifaddrs fonksiyonuna sahip olmalı - man7.org/linux/man-pages/man3/getifaddrs.3.html
tMC

27

im aşağıdaki modülü kullanarak:

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

Tek bir IPv4 tabanlı LAN'da bulunan sistemlerde kullanılmak üzere tasarlanmış pencereler ve linux (ve bunlar için ek modüller gerektirmez) ile test edilmiştir.

Arabirim adlarının sabit listesi, Alexander'ın işaret ettiği gibi öngörülebilir arabirim adlarıyla ilgili systemd v197 değişikliğini benimseyen son linux sürümleri için çalışmaz . Bu gibi durumlarda, listeyi sisteminizdeki arabirim adlarıyla el ile değiştirmeniz veya ağlar gibi başka bir çözüm kullanmanız gerekir .


2
Bu gibi yeni öngörülebilir Linux arabirim adları ile uyumsuz enp0s25. Daha fazla bilgi için bkz. Wiki.archlinux.org/index.php/Network_Configuration#Device_names
Alexander

2
Python 3.4 kullanıyordum ve 'struct.pack (...)' bölümünün 'struct.pack (' 256s ', bayt (ifname [: 15],' utf-8 '))' olarak değiştirilmesi gerekiyordu. Bu soruya bakın: stackoverflow.com/q/27391167/76010
Bakanekobrain

1
Raspbian on Python 2.7.3 - bytes () 2. argümanı beğenmedi. Ama bu işe yaradı: struct.pack('256s', bytes(ifname[:15]))
colm.anseo

24

Bunu ubuntu makinelerimde kullanıyorum:

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

Bu işe yaramıyor.


Güzel ve basit. Amazon'un Linux AMI'sında da çalışır, ancak yalnızca kökteysem. Aksi takdirde bir hata
alırdım

Yani gavaletz'in dediği gibi "/ sbin / ifconfig" kullanmalısınız. Ayrıca Red Hat 4.1.2-48 üzerinde de çalışır.
IgorGanapolsky

7
2.6'dan beri kullanımdan kaldırıldı. Komutları çalıştırmak için alt işlem modülünü kullanın .
Colin Dunklau

5
Ve ifconfig de kullanımdan kaldırıldı. İproute2 kullanın.
Helmut Grohne

Tüm ips'leri alın: import sh; [ip.split () [1] [5:] filtrede ip için (lambda x: 'inet addr', x, sh.ifconfig (). bölünmüş ("\ n"))]
Gabriel Littman

20

Harici paketleri kullanmak istemiyorsanız ve dışarıdaki İnternet sunucularına güvenmek istemiyorsanız, bu yardımcı olabilir. Google Kod Arama'da bulduğum ve gerekli bilgileri döndürmek için değiştirdiğim bir kod örneği :

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

Kullanımı:

>>> for addr in getIPAddresses():
>>>    print addr
192.168.0.100
10.5.9.207

Buna bağlı olarak windll, bu yalnızca Windows üzerinde çalışacaktır.


Yukarıdaki tek astar çözümü genellikle pencerelerde çalışır. Sorun olan Linux'tur.
ricree

14
+1 Bu teknik en azından makinedeki tüm adresleri döndürmeye çalışır.
Jason R.Combs

1
Bu komut dosyası, ilk adresi döndükten sonra makinemde başarısız oluyor. Hata "AttributeError: 'LP_IP_ADDR_STRING' nesnesi 'ipAddress' özniteliği yok" IPv6 adresi ile ilgisi olduğundan şüpheleniyorum.
Jason R.Combs

1
Sorun şu ki, ilk IP adresi dışında herhangi bir şey için adNode'un kaydı kaldırılmamış. While döngüsünde örneğe bir satır daha ekleyin ve benim için çalışıyor: adNode = adNode.contents
Jason R. Coombs

18

Debian (test edilmiş) ve çoğu Linux'tan şüpheleniyorum ..

import commands

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

MS Windows'da (test edildi)

import socket

socket.gethostbyname(socket.gethostname())

1
MacOS üzerinde çalışmaz:hostname: illegal option -- I\nusage: hostname [-fs] [name-of-host]
Derek 朕 會 功夫

18

Henüz yayınlanmadığına inanmıyorum. Ubuntu 12.04'te python 2.7 ile test ettim.

Bu çözümü şu adreste bulabilirsiniz: 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])

Örnek Sonuç:

>>> get_ip_address('eth0')
'38.113.228.130'

2
Python3, Ubuntu 18.04 üzerinde çalışır; Dizenin bayt olması gerekir: >>> socket.inet_ntoa (fcntl.ioctl (s.fileno (), 0x8915, struct.pack ('256s', 'enp0s31f6' [: 15] .encode ('utf-8') )) [20:24]) '192.168.1.1'
cessor

12

Ninjagecko'nun cevabındaki varyasyon. Bu, UDP yayınına izin veren ve LAN veya internet üzerindeki bir adrese erişim gerektirmeyen herhangi bir LAN üzerinde çalışmalıdır.

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

Bekle, <broadcast>geçerli bir ana bilgisayar adı nasıl ? !! Bu tür sözlü ana bilgisayar adlarından kaç tanesi geçerlidir?
Dev Aggarwal

Bu benim için Ubuntu 20.04 üzerinde çalışıyor - 192.168.0.24 değil 127.0.0.1 değil
Lewis Morris

8

Korkarım ki bunu başka bir bilgisayara bağlayıp IP adresinizi göndermekten başka, platformdan bağımsız iyi bir yol yoktur. Örneğin: findmyipaddress . Bağlandığınız bilgisayar NAT'ın arkasında olmadığı sürece NAT'ın arkasında bir IP adresine ihtiyacınız varsa bunun işe yaramayacağını unutmayın.

İşte Linux'ta çalışan bir çözüm: bir ağ arayüzü ile ilişkili IP adresini alın .


8

Komut satırı araçlarıyla "temiz" çıktı üretmenin basit bir yolu:

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

Sistemdeki tüm IPv4 adreslerini gösterecektir.


1
Tüm IPv4 adreslerini göstermez, çünkü ifconfig size yalnızca birincil adresleri anlatır. Tüm adresleri görmek için iproute2'den "ip" kullanmanız gerekir.
Helmut Grohne

Bu, standart kütüphaneyi soran bir soru için çok fazla kabuklu bir cehennem… Ayrıca, ifconfig'i ayrıştırmak ne taşınabilir ne de tek bir makinede güvenilir bir şekilde çalışmaz.
Dominik George

7

FYI Yöntemi doğrulayabilirim:

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

OS X (10.6,10.5), Windows XP ve iyi yönetilen bir RHEL departman sunucusunda çalışır. Ben sadece bazı çekirdek kesmek yapmak çok az bir CentOS VM üzerinde çalışmadı. Bu durumda, yalnızca 127.0.0.1 adresini kontrol edebilir ve bu durumda aşağıdakileri yapabilirsiniz:

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

Ve sonra ip adresini çıktıdan ayrıştırın. Varsayılan olarak ifconfig dosyasının normal kullanıcının PATH'sinde olmadığı ve bu yüzden komutta tam yolu verdiğime dikkat edilmelidir. Umarım bu yardımcı olur.


7

Bu UnkwnTech'in cevabının bir çeşididir - get_local_addr()ana bilgisayarın birincil LAN ip adresini döndüren bir işlev sağlar . Gönderiyorum çünkü bu bir şey ekliyor: ipv6 desteği, hata işleme, localhost / linklocal adresleri yok sayılıyor ve bağlanmak için bir TESTNET addr (rfc5737) kullanıyor.

# 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

Bunun gerçekten iyi bir cevap olabileceğini düşündüm .. ama hep geri döndüNone
Jamie Lindsey

@JamieLindsey İşletim sisteminiz, ağ yapılandırmanız hakkında bazı ayrıntılarınız var mı? Ayrıca, bir şey neye benziyor get_local_addr(remove="www.google.com")? socket.errorAtılan _get_local_addr () ile günlüğe kaydetme, teşhis için yardımcı olabilir.
Eli Collins

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

1
Hmm ... iki NIC'li bir sunucuda bu , atanan IP adreslerinden birini verir , ancak üç kez tekrarlanır. Dizüstü bilgisayarımda '127.0.1.1' (üç kez tekrarlandı ...) veriyor ...
bryn

Bana ['fe80::34e8:fe19:1459:2cde%22','fe80::d528:99fb:d572:e289%12', '192.168.56.1', '192.168.1.2']Windows masaüstünde verir .
Nakilon

5

Çoğu linux kutusunda çalışır:

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

5

Bu cevap, LAN IP'sini alma sorununu çözmek için kişisel girişimim, çünkü socket.gethostbyname(socket.gethostname())127.0.0.1 de döndü. Bu yöntem sadece bir LAN bağlantısı gerektirmez. Kod Python 3.x içindir, ancak 2.x için kolayca dönüştürülebilir. UDP Yayınını Kullanma:

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

1
Bunu aynı ağdaki iki makinede aynı anda çalıştırırsanız ne olur? Mesajınızı ağda yayınladığınızda, tüm makineler 'LAN IP adresim nedir? Udp_listening_server mesajınız 'IP adresiniz xxx'dir' iletisini yanıtlayabilir.
Nicolas Defranoux

4

127.0.1.1 olan gerçek IP adresi. Daha genel olarak konuşursak, bir bilgisayarın herhangi bir sayıda IP adresi olabilir. Bunları özel ağlar için filtreleyebilirsiniz - 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12 ve 192.168.0.0/16.

Ancak, tüm IP adreslerini almanın platformlar arası bir yolu yoktur. Linux'ta SIOCGIFCONFioctl kullanabilirsiniz .


2
Dışarıdan görünen IP'si anlamına geliyor. 127. *. *. * Aralığı tipik olarak localhost veya dahili bir ağ anlamına gelir;
Cerin

4

IP komutunu kullanan ve IPv4 ve IPv6 adreslerini döndüren komut sürümünün hafif bir şekilde iyileştirilmesi:

import commands,re,socket

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

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

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

#Get IPv6 addresses
ipv6s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if ':' in addr)]

4

Mevcut IP adresinizi öğrenmek için GNU / Linux üzerinde "ip route" komutunu kullanabilirsiniz.

Bu, yönlendiriciye / modeme çalışan DHCP sunucusu tarafından arabirime verilen IP'yi gösterir. Genellikle "192.168.1.1/24" yerel ağ için IP'dir, burada "24" maske aralığı içinde DHCP sunucusu tarafından verilen olası IP adresleri aralığı anlamına gelir.

İşte bir örnek: PyNotify'ın sadece amacımı düzeltmek için bir ek olduğunu ve hiç gerekli olmadığını unutmayın

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

Bunun avantajı, ağ arayüzünü belirtmenize gerek olmamasıdır. Bir soket sunucusu çalıştırırken oldukça kullanışlıdır

Py_Notify'ı easy_install ve hatta Pip kullanarak kurabilirsiniz:

easy_install py-notify

veya

pip install py-notify

veya python betiği / yorumlayıcısı içinde

from pip import main

main(['install', 'py-notify'])

4

Localhost IP adresinizden farklı bir IPV4 adresi arıyorsanız 127.0.0.1, işte düzgün bir python kodu parçası:

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

Ayrıca tek bir satırda da yazılabilir:

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

Eğer koymak bile localhostiçinde /etc/hostname, kod hala yerel IP adresini verecektir.


4

Linux için, sadece kullanabilirsiniz check_outputait hostname -Iböylece gibi sistem komutu:

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

googlers için sorunun çapraz platform çözümü olduğunu biliyorum
Kasper Skytte Andersen

3

Not: Bu standart kitaplığı kullanmaz, ancak oldukça basittir.

$ pip install pif

from pif import get_public_ip
get_public_ip()

3
sorular stdlib kullanarak IP bulmakla
ilgiliydi

3

netifaces pip ve easy_install üzerinden kullanılabilir. (Biliyorum, temelde değil, ama yüklemeye değer olabilir.)

netifaces, platformlar arasında bazı tuhaflıklara sahiptir:

  • Localhost / geri döngü arabirimi her zaman dahil edilmeyebilir (Cygwin).
  • Adresler protokol başına listelenir (örneğin, IPv4, IPv6) ve protokoller arabirim başına listelenir. Bazı sistemlerde (Linux) her protokol arabirimi çiftinin kendi ilişkili arabirimi vardır (interface_name: n notasyonu kullanılarak), diğer sistemlerde (Windows) tek bir arabirimin her protokol için bir adres listesi olacaktır. Her iki durumda da bir protokol listesi vardır, ancak yalnızca tek bir öğe içerebilir.

İşte oynamak için bazı netifaces kodu:

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.

Yukarıdaki kod bir adresi arayüz adıyla eşleştirmez (anında ebtables / iptables kuralları oluşturmak için yararlıdır). İşte yukarıdaki bilgileri bir arayüzde arayüz adıyla tutan bir sürüm:

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]

Ve hayır, liste kavrayışlarına aşık değilim. Bugünlerde beynimin çalışma şekli bu.

Aşağıdaki kod parçası hepsini basacaktır:

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)

Zevk almak!


netifaces gerçekten bu sorunu ele alırken hayatı çok kolaylaştırır.
Drake Guan

3

Yeni tanıtılan asyncio paketini kullanan bir Python 3.4 sürümü.

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

Bu UnkwnTech'in mükemmel cevabına dayanmaktadır .


3

IP adresini almak için doğrudan python'da bir kabuk komutu kullanabilirsiniz :

import socket, subprocess

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

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

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

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

ip_addr, hostname = getIpAndHostname()
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.