Python의 stdlib를 사용하여 로컬 IP 주소 찾기


545

파이썬 라이브러리에서 표준 라이브러리 만 사용하여 로컬 IP 주소 (예 : 192.168.xx 또는 10.0.xx)를 어떻게 찾을 수 있습니까?


7
로컬 IP? 아니면 공개 IP? 여러 개의 IP가있는 시스템을 어떻게 다룰 예정입니까?
Sargun Dhillon

사용 ifconfig -a하고 거기에서 출력 ... 사용
프레드릭 Pihl

16
@Fredrik 그건 나쁜 생각입니다. 우선, 당신은 불필요하게 새로운 프로세스를 포기하고 있으며, 이로 인해 프로그램이 단단히 잠긴 구성에서 작동하지 않을 수 있습니다 (또는 프로그램에 필요하지 않은 권한을 허용해야 함). 둘째, 로케일이 다른 사용자에게 버그를 소개합니다. 셋째로, 새로운 프로그램을 시작하기로 결정 했다면 , 더 이상 사용되지 않는 프로그램을 시작해서는 안됩니다. ip addr훨씬 더 적합하고 (파싱하기 쉽고 부팅하기 쉽습니다).
phihag

12
@phihag 당신은 절대적으로 정확합니다, 내 어리 석음을 수정 해 주셔서 감사합니다
Fredrik Pihl

1
여기서 더 근본적인 문제는 올바르게 작성된 최신 네트워킹 프로그램에서 로컬 IP 주소의 올바른 (집합)은 피어 또는 잠재적 인 피어 세트에 따라 달라진다는 것입니다. 로컬 IP 주소가 bind특정 인터페이스의 소켓에 필요한 경우 정책 문제입니다. 피어가 로컬 컴퓨터에 대한 연결을 다시 열 수 있도록 피어가 "콜백"할 수 있도록 로컬 IP 주소를 피어에 전달해야하는 경우 상황은 NAT (Network Address Translation)가 있는지 여부에 따라 다릅니다. 사이에 상자. NAT가 없으면 getsockname좋은 선택입니다.
Pekka Nikander

답변:


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

이것은 항상 작동하지는 않습니다 ( 127.0.0.1호스트 이름이 (으) /etc/hosts로 표시된 컴퓨터에서 반환 127.0.0.1), 완화는 gimel이 보여주는 socket.getfqdn()것입니다. 대신 사용하십시오. 물론 컴퓨터에는 분석 가능한 호스트 이름이 필요합니다.


43
이것은 플랫폼 독립적 인 솔루션이 아니라는 점에 유의해야합니다. 이 방법을 사용하면 많은 Linux에서 IP 주소로 127.0.0.1을 반환합니다.
Jason Baker

20
변형 : socket.gethostbyname (socket.getfqdn ())
gimel

55
단일 IP 주소 만 반환하는 것으로 보입니다. 기계에 여러 개의 주소가있는 경우 어떻게합니까?
Jason R. Coombs

26
우분투에서는 어떤 이유로 127.0.1.1을 반환합니다.
5

13
@Jason R. Coombs, 다음 코드를 사용하여 호스트 시스템에 속하는 IPv4 주소 목록을 검색하십시오.socket.gethostbyname_ex(socket.gethostname())[-1]
Barmaley

460

방금 이것을 찾았지만 약간 hackish처럼 보이지만 * 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()

인터넷에 연결되어 있고 로컬 프록시가 없다고 가정합니다.


31
컴퓨터에 여러 인터페이스가 있고 gmail.com으로 라우팅되는 인터페이스가 필요하다면 좋을 것입니다
elzapp

4
s.connect ()에 의해 발생할 수있는 socket.error 예외를 포착하는 것이 좋습니다.
phobie

39
도메인 이름 대신 IP 주소를 사용하는 것이 좋습니다. DNS 가용성과 더 빠르고 독립적이어야합니다. 예를 들어 Google의 퍼블릭 DNS 서버 인 8.8.8.8 IP를 사용할 수 있습니다.
wobmene

10
매우 영리하고 완벽하게 작동합니다. 해당되는 경우 gmail 또는 8.8.8.8 대신 보려는 서버의 IP 또는 주소를 사용할 수도 있습니다.
Falken 교수 계약은

3
이 예는 실제로 gmail.com을 해결할 수있는 외부 종속성이 있습니다. 로컬 LAN에 있지 않은 IP 주소로 설정하면 (업 / 다운 상태에 관계없이) 네트워크 트래픽 없이도 작동하지 않습니다.
grim

253

이 메소드는 로컬 박스의 "기본"IP (기본 경로가있는 IP)를 반환합니다 .

  • 라우팅 가능한 인터넷 액세스 또는 연결이 전혀 필요하지 않습니다.
  • 모든 인터페이스가 네트워크에서 분리 된 경우에도 작동합니다.
  • 다른 곳으로 가거나 필요로하지 않습니다 .
  • NAT, 공개, 개인, 외부 및 내부 IP와 호환
  • 외부 의존성이없는 순수 파이썬 2 (또는 3).
  • Linux, Windows 및 OSX에서 작동합니다.

파이썬 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) 인 단일 IP를 반환합니다. 대신 모든 인터페이스 (로컬 호스트 포함)에 연결된 모든 IP가 필요한 경우이 답변을 참조하십시오 .

집에서 Wi-Fi 상자와 같은 NAT 방화벽 뒤에 있으면 공용 NAT IP가 표시되지 않고 로컬 WIFI 라우터에 대한 기본 경로가있는 로컬 네트워크의 개인 IP가 표시됩니다. 와이파이 라우터의 외부 IP를 얻으려면 THAT 상자에서이를 실행하거나 IP를 반영 할 수있는 whatismyip.com/whatismyipaddress.com과 같은 외부 서비스에 연결해야하지만 원래 질문과는 완전히 다릅니다. :)


7
Python 2 및 3과 함께 Raspbian에서 작동합니다!
pierce.jason

3
훌륭한. VM을 포함한 Win7,8,8.1 + Linux Mint & Arch에서 작동합니다.
shermy

2
Windows 10 Pro에서 작동합니다! Jamieson Becker 감사합니다!
varantes

3
어떤 이유로 Mac OS X El Capitan 10.11.6에서는 작동하지 않습니다 (예외 OS 오류 : [Errno 49] 요청한 주소를 할당 할 수 없음). 포트를 '0'에서 '1'로 변경 : s.connect (( '10.255.255.255', 1))는 Mac OS X 및 Linux에서 모두 작동했습니다. 우분투 17.04
Pedro Scarapicchia Junior

9
이것이 정답입니다. socket.gethostbyname(socket.gethostname())끔찍한 결과를 제공합니다.
Jason Floyd

142

이라는 별칭으로 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])'"
  • 현재 IPv4 주소를 찾기 위해 Python 2.x, Python 3.x, 최신 및 이전 Linux 배포판, OSX / macOS 및 Windows에서 올바르게 작동합니다.
  • 여러 개의 IP 주소, IPv6, 구성된 IP 주소 또는 인터넷 액세스가없는 컴퓨터의 경우 올바른 결과를 반환하지 않습니다.

위와 동일하지만 Python 코드 만 :

import socket
print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1], [[(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])
  • IP 주소가 구성되어 있지 않으면 예외가 발생합니다.

인터넷에 연결되지 않은 LAN에서도 작동하는 버전 :

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

이것은 Linux 및 Windows에서 Python 2 및 3에서 작동하지만 여러 네트워크 장치 또는 IPv6을 처리하지 않습니다. 그러나 최근 Linux 배포판에서 작동을 멈췄으므로 대신이 대체 기술을 사용해 보았습니다. 8.8.8.8포트 에서 Google DNS 서버에 연결을 시도합니다 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 주소를 찾는 것이 여기에 나열된 방법보다 훨씬 강력하고 신뢰할 수 있습니다.


2
@Alexander :이 답변이 예전보다 훨씬 유용하지 않다고 말하면 복제물을 걸러내는 것이 중요하지 않습니다. 문서에 따르면 socket.getaddrinfo()플랫폼에서 일관되게 작동해야하지만 Linux에서만 확인했지만 다른 운영 체제는 신경 쓰지 않았습니다.
Wladimir Palant

1
@Alexander, /etc/resolve.conf: No such file or directory그리고로 표시된 로컬 IPv4 주소가 ifconfig있습니다.
anatoly techtonik

2
업데이트 된 버전이 Python2 및 Py3k와 함께 Ubuntu 14.04에서 작동하는지 확인할 수 있습니다.
Uli Köhler 2016

4
"update"는 UDP 소켓에서 connect ()를 사용하는 좋은 방법을 보여줍니다. 트래픽을 보내지 않지만 지정된 수신자에게 패킷의 보낸 사람 주소를 찾을 수 있습니다. 포트가 관련이 없을 수 있습니다 (0도 작동해야 함). 멀티 홈 호스트에서는 올바른 서브넷에서 주소를 선택하는 것이 중요합니다.
피터 한센

16
한 줄에 코드를 작성할 수 있다고해서 반드시 그렇게해야한다는 것은 아닙니다.
JackLeo

91

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에서 작동한다고 주장합니다.


20
질문에 명시된 바와 같이 추가 설치가 필요하지 않으므로 기본 설치에서 무언가를 원합니다.
UnkwnTech

4
netifaces가 Windows에서 IPv6을 지원하지 않고 유지 관리되지 않는 것 외에는 이것이 제가 가장 좋아하는 대답입니다. 누구든지 Windows에서 IPv6 주소를 얻는 방법을 알고 있습니까?
Jean-Paul Calderone

3
netifaces는 py3k를 지원하지 않으며 Windows의 PITA 인 C 컴파일러가 필요합니다.
Matt Joiner 2016 년

4
@MattJoiner이 둘 중 어느 것도 더 이상 사실이 아닙니다 (최신 버전은 PyPI에 Windows 바이너리가 있고 Py3K를 지원합니다).
alastair

4
@ Jean-PaulCalderone FWIW에서 최신 버전의 netifaces Windows에서 IPv6을 지원합니다.
alastair

47

소켓 API 방법

참조 https://stackoverflow.com/a/28950776/711085를

단점 :

  • 크로스 플랫폼이 아닙니다.
  • 인터넷상의 특정 주소의 존재와 관련하여 더 많은 대체 코드가 필요합니다.
  • NAT 뒤에 있으면 작동하지 않습니다.
  • 아마도 (일반적으로 ISP의) DNS 가용성과 무관하게 UDP 연결을 생성합니다 (8.8.8.8 : Google (동시 DNS 서버) 사용과 같은 아이디어에 대한 다른 답변 참조)
  • 사용하지 않는 것으로 지정된 숫자 IP 주소와 같이 대상 주소를 도달 할 수없는 상태로 만들어야합니다. fakesubdomain.google.com 또는 somefakewebsite.com과 같은 도메인을 사용하지 마십시오. 여전히 해당 당사자 (현재 또는 미래)에 스팸을 보내고 프로세스에서 자신의 네트워크 상자에 스팸을 발송합니다.

반사판 방법

(이것은 192.168과 같은 로컬 IP 주소의 OP 질문에 대답하지 않습니다. 공용 IP 주소를 제공하므로 사용 사례에 따라 더 바람직 할 수 있습니다.)

whatismyip.com과 같은 일부 사이트 (예 : API)를 다음과 같이 쿼리 할 수 ​​있습니다.

from urllib.request import urlopen
import re
def getPublicIp():
    data = str(urlopen('http://checkip.dyndns.com/').read())
    # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'

    return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)

또는 python2를 사용하는 경우 :

from urllib import urlopen
import re
def getPublicIp():
    data = str(urlopen('http://checkip.dyndns.com/').read())
    # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'

    return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)

장점 :

  • 이 방법의 한 가지 장점은 크로스 플랫폼입니다
  • 추한 NAT (예 : 홈 라우터) 뒤에서 작동합니다.

단점 (및 해결 방법) :

  • 이 웹 사이트가 작동하고 형식이 변경되지 않고 (거의 확실하지는 않음) DNS 서버가 작동해야합니다. 장애 발생시 다른 타사 IP 주소 리플렉터를 쿼리하여이 문제를 완화 할 수 있습니다.
  • 여러 리플렉터를 쿼리하지 않은 경우 (손상된 리플렉터가 사용자의 주소가 아닌 주소임을 알려주지 않도록) 또는 HTTPS를 사용하지 않는 경우 (중간자 공격을 방지하기 위해) 서버가된다)

편집 : 처음에는 이러한 방법이 실제로 좋지 않다고 생각했지만 (많은 폴백을 사용하지 않으면 코드가 몇 년 후에는 관련이 없을 수 있음) "인터넷이란 무엇입니까?"라는 질문을 제기합니다. 컴퓨터에는 많은 다른 네트워크를 가리키는 많은 인터페이스가있을 수 있습니다. 주제에 대한 자세한 설명은gateways and routes. 컴퓨터는 내부 게이트웨이를 통해 내부 네트워크에 액세스하거나 라우터 (일반적으로 경우)와 같은 게이트웨이를 통해 월드 와이드 웹에 액세스 할 수 있습니다. OP가 요청하는 로컬 IP 주소는 단일 링크 계층에 대해서만 잘 정의되어 있으므로 "네트워크 카드 또는 이더넷 케이블입니까?"라고 지정해야합니다. . 제시된대로이 질문에 대한 고유하지 않은 답변이 여러 개있을 수 있습니다. 그러나 월드 와이드 웹의 글로벌 IP 주소는 아마도 대규모 네트워크 조각화가없는 경우 잘 정의되어있을 것입니다. 아마도 TLD에 액세스 할 수있는 게이트웨이를 통한 리턴 경로 일 것입니다.


NAT 뒤에있는 경우 LAN 전체 주소를 반환합니다. 인터넷에 연결하는 경우 공용 IP 주소 중 하나를 반환하는 웹 서비스에 연결할 수 있습니다.
phihag 2016 년

UDP 연결을 생성하기 때문에 TCP 연결을 생성하지 않습니다.
Anuj Gupta

2
소켓 API 버전의 대안으로 s.connect (( 'INSERT SOME TARGET WEBSITE.com', 0))을 s.setsockopt (socket.SOL_SOCKET, socket.SO_BROADCAST, 1); s.connect (( '' broadcast> ', 0))) DNS 조회를 피하십시오. (방화벽이 있으면 브로드 캐스트에 문제가있을 수 있습니다)
dlm

45

컴퓨터에 인터넷 경로가 있으면 / etc / hosts가 올바르게 설정되지 않은 경우에도 항상 선호하는 로컬 IP 주소를 가져옵니다.

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 서버는 로컬 DNS 서버로 할 수 있습니까?
Ciasto piekarz

39

Linux에서 :

>>> import socket, struct, fcntl
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> sockfd = sock.fileno()
>>> SIOCGIFADDR = 0x8915
>>>
>>> def get_ip(iface = 'eth0'):
...     ifreq = struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)
...     try:
...         res = fcntl.ioctl(sockfd, SIOCGIFADDR, ifreq)
...     except:
...         return None
...     ip = struct.unpack('16sH2x4s8x', res)[2]
...     return socket.inet_ntoa(ip)
... 
>>> get_ip('eth0')
'10.80.40.234'
>>> 

그래서 이것은 아무런 효과가없는 소켓을 효과적으로 열고 로컬 IP를 얻기 위해 해당 소켓에 대한 원시 데이터를 확인합니까?
Dave

1
소켓이 열려 fd가 커널과 통신 할 수 있도록합니다 (을 통해 ioctl). 소켓은 사용자 공간과 커널 간의 통신 메커니즘에 대한 addr 정보를 원하는 인터페이스에 바인딩되지 않습니다. en.wikipedia.org/wiki/Ioctl lxr.free-electrons.com/source/net/socket.c
tMC

2
한 번의 수정으로 Python3에서 작동 : 다음 struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)으로 대체되어야합니다.struct.pack('16sH14s', iface.encode('utf-8'), socket.AF_INET, b'\x00'*14)
pepoluan

1
@ChristianFischer ioctl는 IPv6를 지원하지 않는다고 생각하지 않을 레거시 인터페이스입니다. '올바른'방법은 Netlink를 통한 것이라고 생각하지만 파이썬에서는 그다지 간단하지 않습니다. 나는 libc가 작동 getifaddrs할 수있는 파이썬ctypes 모듈을 통해 액세스 할 수있는 기능 을 가지고 있어야한다고 생각합니다 -man7.org/linux/man-pages/man3/getifaddrs.3.html
tMC

1
@Maddy ioctl은 IPv6를 지원하지 않는다고 생각하지 않을 레거시 인터페이스입니다. '올바른'방법은 Netlink를 통한 것이라고 생각하지만 파이썬에서는 그다지 간단하지 않습니다. 나는 libc의 액세스를 통해 비단뱀하는 ctypes 모듈을 작동 할 수있는 할 수있는 기능의 getifaddrs을해야한다고 생각 - man7.org/linux/man-pages/man3/getifaddrs.3.html
TMC

27

다음 모듈을 사용하는 메신저 :

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

단일 IPv4 기반 LAN에있는 시스템에서 사용하기 위해 Windows 및 Linux로 테스트되었으며 추가 모듈이 필요하지 않습니다.

Alexander가 지적한대로 예측 가능한 인터페이스 이름과 관련하여 systemd v197 변경 사항을 채택한 최신 Linux 버전에서는 고정 된 인터페이스 이름 목록이 작동하지 않습니다 . 이러한 경우 목록을 시스템의 인터페이스 이름으로 수동으로 바꾸거나 netifaces 와 같은 다른 솔루션을 사용해야 합니다.


2
이 같은 예측 가능한 새로운 Linux 인터페이스 이름과 호환되지 않습니다 enp0s25. 자세한 내용은 wiki.archlinux.org/index.php/Network_Configuration#Device_names
Alexander

2
파이썬 3.4를 사용하고 있었고 'struct.pack (...)'부분을 'struct.pack ('256s ', bytes (ifname [: 15],'utf-8 '))'로 변경해야했습니다. 이 질문을 참조하십시오 : stackoverflow.com/q/27391167/76010
Bakanekobrain

1
Python 2.7.3이있는 Raspbian에서 bytes ()는 두 번째 인수를 좋아하지 않았습니다. 그러나 이것은 효과가 있었다 : struct.pack('256s', bytes(ifname[:15]))
colm.anseo

24

우분투 머신에서 이것을 사용합니다 :

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

작동하지 않습니다.


좋고 간단합니다. Amazon의 Linux AMI에서도 작동하지만 루트 인 경우에만 작동합니다. 그렇지 않으면 오류가 발생합니다 것 '쉬 : ifconfig를 : 명령을 찾을 수 없음'
IgorGanapolsky

따라서 gavaletz와 같이 "/ sbin / ifconfig"를 사용해야합니다. Red Hat 4.1.2-48에서도 작동합니다.
IgorGanapolsky 님이

7
2.6부터 사용되지 않습니다. 서브 프로세스 모듈 을 사용하여 명령을 실행 하십시오 .
Colin Dunklau

5
그리고 ifconfig도 더 이상 사용되지 않습니다. iproute2를 사용하십시오.
Helmut Grohne

모든 IP를 가져옵니다. import sh; [ip.split () [1] [5 :] in ip in filter (lambda x : x의 'inet addr', sh.ifconfig (). split ( "\ n"))]
Gabriel Littman

20

외부 패키지를 사용하지 않고 외부 인터넷 서버에 의존하지 않으려는 경우 도움이 될 수 있습니다. Google 코드 검색 에서 찾은 코드 샘플이며 필요한 정보를 반환하도록 수정되었습니다.

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

에 의존하기 때문에 이것은 windllWindows에서만 작동합니다.


위의 하나의 라이너 솔루션은 일반적으로 Windows에서 작동합니다. 문제가되는 것은 Linux입니다.
ricree

14
+1이 기술은 최소한 머신의 모든 주소를 반환하려고 시도합니다.
Jason R. Coombs

1
이 스크립트는 첫 번째 주소를 반환 한 후 컴퓨터에서 실패합니다. 오류는 "AttributeError : 'LP_IP_ADDR_STRING'객체에 'ipAddress'속성이 없습니다."IPv6 주소와 관련이있는 것 같습니다.
Jason R. Coombs

1
문제는 첫 번째 IP 주소 이외의 경우 adNode가 역 참조되지 않는다는 것입니다. while 루프에서 예제에 한 줄을 더 추가하면 저에게 효과적입니다. adNode = adNode.contents
Jason R. Coombs

18

데비안 (테스트)에서 나는 대부분의 리눅스를 의심한다.

import commands

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

MS Windows에서 (테스트 된)

import socket

socket.gethostbyname(socket.gethostname())

1
macOS에서는 작동하지 않습니다 :hostname: illegal option -- I\nusage: hostname [-fs] [name-of-host]
Derek 朕 會 功夫

18

아직 게시되지 않은 버전입니다. 우분투 12.04에서 Python 2.7로 테스트했습니다.

http://code.activestate.com/recipes/439094-get-the-ip-address-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'

2
Python3, Ubuntu 18.04에서 작동합니다. 문자열은 바이트 여야합니다. >>> socket.inet_ntoa (fcntl.ioctl (s.fileno (), 0x8915, struct.pack ( '256s', 'enp0s31f6'[: 15] .encode ( 'utf-8')) )) 20시 24분]) '192.168.1.1'
cessor

12

ninjagecko의 답변에 변형. UDP 브로드 캐스트를 허용하고 LAN 또는 인터넷의 주소에 액세스 할 필요가없는 모든 LAN에서 작동해야합니다.

import socket
def getNetworkIp():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    s.connect(('<broadcast>', 0))
    return s.getsockname()[0]

print (getNetworkIp())

잠깐, <broadcast>유효한 호스트 이름은 어떻습니까? !! 이러한 종류의 언어 호스트 이름은 몇 개입니까?
Dev Aggarwal

이것은 우분투 20.04에서 나를 위해 작동합니다-127.0.0.1이 아닌 192.168.0.24 받기
Lewis Morris


8

명령 줄 유틸리티를 통해 "깨끗한"출력을 생성하는 간단한 방법 :

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

시스템의 모든 IPv4 주소가 표시됩니다.


1
ifconfig는 기본 주소 만 알려주므로 모든 IPv4 주소를 표시하지는 않습니다. 모든 주소를 보려면 iproute2에서 "ip"를 사용해야합니다.
Helmut Grohne

그것은 표준 라이브러리를 요구하는 질문에 대한 많은 쉘입니다.…
Dominik George

7

참고로 방법이 다음과 같은지 확인할 수 있습니다.

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

OS X (10.6,10.5), Windows XP 및 잘 관리 된 RHEL 부서 서버에서 작동합니다. 커널 해킹을 수행하는 매우 작은 CentOS VM에서는 작동하지 않았습니다. 따라서 해당 인스턴스의 경우 127.0.0.1 주소를 확인하고이 경우 다음을 수행하십시오.

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

그런 다음 출력에서 ​​IP 주소를 구문 분석하십시오. ifconfig가 기본적으로 일반 사용자의 PATH에 있지 않으므로 명령에 전체 경로를 제공하는 것입니다. 이게 도움이 되길 바란다.


7

이것은 UnkwnTech의 답변의 변형입니다 get_local_addr(). 호스트의 기본 LAN IP 주소를 반환 하는 기능을 제공 합니다. ipv6 지원, 오류 처리, localhost / linklocal addrs 무시 및 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 OS, 네트워크 구성에 대한 세부 정보가 있습니까? 또한 무엇을 get_local_addr(remove="www.google.com")반환합니까? socket.error_get_local_addr ()에 의해 발생 된 로깅 은 진단에 도움이 될 수 있습니다.
Eli Collins

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

1
흠 ... NIC가 두 개인 서버 에서는 할당 된 IP 주소 중 하나 를 제공 하지만 세 번 반복됩니다. 내 노트북에는 '127.0.1.1'이 표시됩니다 (3 회 반복 ...).
bryn

['fe80::34e8:fe19:1459:2cde%22','fe80::d528:99fb:d572:e289%12', '192.168.56.1', '192.168.1.2']Windows 바탕 화면에서 제공합니다 .
Nakilon

5

이것은 대부분의 리눅스 박스에서 작동합니다 :

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

이 답변은 socket.gethostbyname(socket.gethostname())127.0.0.1을 반환 했기 때문에 LAN IP를 얻는 문제를 해결하려는 개인적 시도 입니다. 이 방법은 인터넷 만 LAN 연결이 필요하지 않습니다. 코드는 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())

1
동일한 네트워크의 두 컴퓨터에서 동시에이 작업을 실행하면 어떻게됩니까? 네트워크에서 메시지를 브로드 캐스트하면 모든 시스템에 '내 LAN IP 주소 란 무엇입니까? udp_listening_server가 메시지에 '귀하의 IP 주소는 xxx'입니다.
Nicolas Defranoux

4

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에서는 SIOCGIFCONFioctl을 사용할 수 있습니다 .


2
그는 외부에서 볼 수있는 IP를 의미합니다. 127. *. *. * 범위는 일반적으로 로컬 호스트 또는 내부 네트워크를 나타내며, 원하는 것은 아닙니다.
Cerin

4

IP 명령을 사용하고 IPv4 및 IPv6 주소를 반환하는 명령 버전이 약간 수정되었습니다.

import commands,re,socket

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

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

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

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

4

GNU / Linux에서 "ip route"명령을 사용하여 현재 IP 주소를 알 수 있습니다.

라우터 / 모뎀에서 실행되는 DHCP 서버가 인터페이스에 제공 한 IP를 보여줍니다. 일반적으로 "192.168.1.1/24"는 로컬 네트워크의 IP이며 "24"는 마스크 범위 내에서 DHCP 서버가 제공 한 가능한 IP 주소 범위를 의미합니다.

예를 들면 다음과 같습니다. 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()    

이것의 장점은 네트워크 인터페이스를 지정할 필요가 없다는 것입니다. 소켓 서버를 실행할 때 매우 유용합니다.

easy_install 또는 Pip을 사용하여 PyNotify를 설치할 수 있습니다.

easy_install py-notify

또는

pip install py-notify

또는 파이썬 스크립트 / 통역사

from pip import main

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

4

로컬 호스트 IP 주소 127.0.0.1와 다른 IPV4 주소를 찾고 있다면 다음은 깔끔한 파이썬 코드입니다.

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 주소를 제공 할 것입니다.



3

참고 : 이것은 표준 라이브러리를 사용하지 않지만 매우 간단합니다.

$ pip 설치 pif

from pif import get_public_ip
get_public_ip()

3
질문은 IP 사용하여 다음 stdlib을 찾는 것에 대해이었다
Alexandru 시릴

3

netifaces는 pip 및 easy_install을 통해 사용할 수 있습니다. (나는 기본이 아니지만 설치 가치가 있음을 알고 있습니다.)

netifaces는 플랫폼에 따라 몇 가지 이상한 점이 있습니다.

  • 로컬 호스트 / 루프백 인터페이스가 항상 포함되는 것은 아닙니다 (Cygwin).
  • 주소는 프로토콜별로 표시되고 (예 : IPv4, IPv6) 프로토콜은 인터페이스별로 표시됩니다. 일부 시스템 (Linux)에서 각 프로토콜-인터페이스 쌍에는 고유 한 관련 인터페이스 (interface_name : n 표기법 사용)가 있고 다른 시스템 (Windows)에서는 단일 인터페이스에 각 프로토콜의 주소 목록이 있습니다. 두 경우 모두 프로토콜 목록이 있지만 단일 요소 만 포함 할 수 있습니다.

재생할 netifaces 코드는 다음과 같습니다.

import netifaces

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

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

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

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

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

위의 코드는 주소를 인터페이스 이름에 다시 매핑하지 않습니다 (즉석에서 ebtables / iptables 규칙을 생성하는 데 유용함). 위의 정보를 인터페이스 이름과 함께 튜플에 유지하는 버전이 있습니다.

import netifaces

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

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

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

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

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

그리고 아니, 나는 목록 이해와 사랑에 빠지지 않습니다. 요즘 내 뇌가 작동하는 방식 일뿐입니다.

다음 스 니펫은 모두 인쇄합니다.

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

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

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

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

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

즐겨!


netifaces는이 문제를 다루는 동안 인생을 정말 쉽게 해줍니다.
Drake Guan

3

새로 도입 된 asyncio 패키지를 사용하는 Python 3.4 버전입니다.

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의 탁월한 답변을 기반으로 합니다.


3

IP 주소를 얻으려면 파이썬 에서 직접 쉘 명령을 사용할 수 있습니다 .

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()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.