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

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



답변

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

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


답변

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

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


답변

이 메소드는 로컬 박스의 “기본”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과 같은 외부 서비스에 연결해야하지만 원래 질문과는 완전히 다릅니다. 🙂


답변

이라는 별칭으로 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 주소를 찾는 것이 여기에 나열된 방법보다 훨씬 강력하고 신뢰할 수 있습니다.


답변

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


답변

소켓 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에 액세스 할 수있는 게이트웨이를 통한 리턴 경로 일 것입니다.


답변

컴퓨터에 인터넷 경로가 있으면 / 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]