1. 내부 IP & 외부 IP
- socket + getsockname() → 내부 IP 확인
- urllib 또는 http.client + api.ipify.org → 외부 IP 확인
### ===== 내부 IP 확인 =====
import socket # 네트워크 소켓 통신을 위한 표준 라이브러리
import urllib.request # HTTP 요청을 보낼 수 있는 표준 라이브러리
import json # JSON 형식 데이터를 파싱하기 위한 라이브러리
import ssl # SSL 인증서 처리 라이브러리
in_addr = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP 소켓 객체 생성 (IPv4, TCP 방식)
in_addr.connect(("www.google.com", 443)) # 구글 서버(443: HTTPS 포트)에 연결 → 내 PC의 네트워크 인터페이스가 사용됨
print("내부 IP : ", in_addr.getsockname()[0]) # 소켓이 사용한 내 PC의 IP 주소를 가져와 출력
### ===== 외부 IP - 표준 라이브러리(1) urllib 활용 =====
# SSL 인증서 검증을 비활성화 (테스트용; 보안적으로는 권장되지 않음)
ssl._create_default_https_context = ssl._create_unverified_context
with urllib.request.urlopen(url) as response: # 지정한 URL로 HTTPS 요청 전송
data = response.read().decode("utf-8") # 응답(body)을 읽고 UTF-8 문자열로 디코딩
ip = json.loads(data)["ip"] # JSON 문자열을 파싱 후, "ip" 키 값만 추출
print("외부 IP 주소: ", ip) # 외부 IP 출력
### ===== 외부 IP - 표준 라이브러리(2) http.client 활용 =====
import http.client # HTTP 요청을 저수준으로 다룰 수 있는 표준 라이브러리
import json # JSON 파싱 라이브러리 (다시 import해도 무방)
import ssl # SSL 인증서 관련 라이브러리 (다시 import해도 무방)
# SSL 인증서 검증을 비활성화한 context 생성 (로컬 테스트용)
context = ssl._create_unverified_context()
conn = http.client.HTTPSConnection("api.ipify.org", context = context) # api.ipify.org에 HTTPS 연결 생성
conn.request("GET", "/?format=json") # GET 요청 보내기
res = conn.getresponse() # 서버로부터 응답 받기
data = res.read().decode("utf-8") # 응답 내용을 읽어서 UTF-8 문자열로 변환
ip = json.loads(data)["ip"] # JSON 파싱 후, "ip" 값 추출
print("외부 IP 주소: ", ip) # 외부 IP 출력
2. 함수로 정리
- get_internal_ip(), get_external_ip_urllib(), get_external_ip_httpclient() 형태로 호출할 수 있게 정리
import socket # 네트워크 소켓(통신) 기능 제공
import urllib.request # 고수준 HTTP(S) 요청을 보낼 수 있는 표준 라이브러리
import http.client # 저수준 HTTP(S) 요청을 다루는 표준 라이브러리
import json # JSON 문자열 ↔ 파이썬 객체 변환
import ssl # SSL/TLS 인증서 검증 및 컨텍스트 설정
def get_internal_ip(target_host="www.google.com", port=443, timeout=5):
"""
내부(사설) IP를 추출합니다.
원리: 외부 서버에 소켓으로 연결하면, OS가 사용할 네트워크 인터페이스를 선택하는데,
그때 소켓의 로컬 주소에 내부 IP가 담깁니다.
"""
# 외부 서버(기본: 구글 443)로 TCP 연결을 생성 (타임아웃 설정)
with socket.create_connection((target_host, port), timeout=timeout) as s:
# 연결된 소켓의 로컬 주소(내 컴퓨터 측 주소)를 얻고, 그중 IP만 추출
return s.getsockname()[0]
def get_external_ip_urllib(verify_ssl=True, timeout=5):
"""
외부(공인) IP를 urllib로 조회합니다.
기본은 SSL 인증서 검증을 수행(verify_ssl=True). 검증 문제 시 False로 끌 수 있습니다(테스트용).
"""
# 외부 IP를 JSON으로 반환하는 공개 API URL
# SSL 컨텍스트 생성: 검증 모드/비검증 모드 선택
context = ssl.create_default_context() if verify_ssl else ssl._create_unverified_context()
# 지정 URL로 HTTPS 요청을 보냄 (컨텍스트/타임아웃 지정)
with urllib.request.urlopen(url, context=context, timeout=timeout) as resp:
# 응답 본문 바이트를 읽고 UTF-8로 디코딩
body = resp.read().decode("utf-8")
# JSON 문자열을 파싱하고 "ip" 필드만 추출
return json.loads(body)["ip"]
def get_external_ip_httpclient(verify_ssl=True, timeout=5):
"""
외부(공인) IP를 http.client로 조회합니다.
기본은 SSL 인증서 검증을 수행(verify_ssl=True). 검증 문제 시 False로 끌 수 있습니다(테스트용).
"""
# SSL 컨텍스트 생성: 검증 모드/비검증 모드 선택
context = ssl.create_default_context() if verify_ssl else ssl._create_unverified_context()
# HTTPS 연결 객체를 생성 (호스트: api.ipify.org, SSL 컨텍스트/타임아웃 적용)
conn = http.client.HTTPSConnection("api.ipify.org", context=context, timeout=timeout)
try:
# GET 요청 전송 (경로에 ?format=json 쿼리로 JSON을 요청)
conn.request("GET", "/?format=json")
# 서버 응답 객체 수신
res = conn.getresponse()
# 응답 바디를 읽고 UTF-8로 디코딩
body = res.read().decode("utf-8")
# JSON 파싱 후 "ip" 필드만 반환
return json.loads(body)["ip"]
finally:
# 네트워크 리소스 정리를 위해 연결 닫기
conn.close()
# ------ 사용 예시 (직접 실행 시) ------
if __name__ == "__main__":
# 내부 IP 출력 (연결 가능한 외부 호스트를 통해 로컬 인터페이스 확인)
print("내부 IP :", get_internal_ip())
# 외부 IP 출력 - urllib (인증서 검증 ON: 운영 권장)
try:
print("외부 IP (urllib, verify=ON):", get_external_ip_urllib(verify_ssl=True))
except Exception as e:
print("urllib 검증 ON 실패 → 테스트용 비검증으로 재시도:", e)
print("외부 IP (urllib, verify=OFF):", get_external_ip_urllib(verify_ssl=False))
# 외부 IP 출력 - http.client (인증서 검증 ON: 운영 권장)
try:
print("외부 IP (http.client, verify=ON):", get_external_ip_httpclient(verify_ssl=True))
except Exception as e:
print("http.client 검증 ON 실패 → 테스트용 비검증으로 재시도:", e)
print("외부 IP (http.client, verify=OFF):", get_external_ip_httpclient(verify_ssl=False))
(SSL 인증서 문제가 있는 환경을 고려해, verify_ssl 옵션으로 검증을 끄거나 켤 수 있게 했습니다. 운영/배포 환경에선 verify_ssl=True를 권장합니다.)
- 운영/배포: verify_ssl=True 유지(기본값).
- 로컬 테스트에서 인증서 오류 발생: 일시적으로 verify_ssl=False로 호출 → 동작 확인 후, 인증서 환경을 정상화하세요.
- (macOS) Python 설치 경로의 Install Certificates.command 실행
- (Windows/Linux) 시스템 루트 인증서 최신 상태로 유지
3. 클래스로 묶기
- IPFetcher 클래스 안에 get_internal_ip(), get_external_ip_urllib(), get_external_ip_httpclient() 메서드 3개를 넣었습니다.
- verify_ssl, timeout, target_host 등은 생성자에서 기본값 설정 후 메서드에서 사용합니다.
import socket # 네트워크 소켓(통신) 기능 제공
import urllib.request # 고수준 HTTP(S) 요청을 보낼 수 있는 표준 라이브러리
import http.client # 저수준 HTTP(S) 요청을 다루는 표준 라이브러리
import json # JSON 문자열 ↔ 파이썬 객체 변환
import ssl # SSL/TLS 인증서 검증 및 컨텍스트 설정
class IPFetcher:
"""
내부 IP(사설 IP)와 외부 IP(공인 IP)를 조회하는 기능을 제공하는 클래스.
"""
def __init__(self, target_host="www.google.com", port=443, timeout=5, verify_ssl=True):
"""
클래스 초기화.
:param target_host: 내부 IP 확인을 위해 연결할 외부 호스트 (기본: 구글)
:param port: 연결 포트 (기본: 443)
:param timeout: 네트워크 연결 타임아웃 (초)
:param verify_ssl: 외부 IP 조회 시 SSL 인증서 검증 여부 (운영환경: True 권장)
"""
self.target_host = target_host
self.port = port
self.timeout = timeout
self.verify_ssl = verify_ssl
def get_internal_ip(self):
"""
내부(사설) IP 조회.
원리: 외부 호스트에 소켓 연결을 열면, OS가 선택한 네트워크 인터페이스의 로컬 주소(IP)를 알 수 있음.
"""
with socket.create_connection((self.target_host, self.port), timeout=self.timeout) as s:
return s.getsockname()[0]
def get_external_ip_urllib(self):
"""
외부(공인) IP 조회 - urllib 사용.
:return: 외부 IP 문자열
"""
context = ssl.create_default_context() if self.verify_ssl else ssl._create_unverified_context()
with urllib.request.urlopen(url, context=context, timeout=self.timeout) as resp:
body = resp.read().decode("utf-8")
return json.loads(body)["ip"]
def get_external_ip_httpclient(self):
"""
외부(공인) IP 조회 - http.client 사용.
:return: 외부 IP 문자열
"""
context = ssl.create_default_context() if self.verify_ssl else ssl._create_unverified_context()
conn = http.client.HTTPSConnection("api.ipify.org", context=context, timeout=self.timeout)
try:
conn.request("GET", "/?format=json")
res = conn.getresponse()
body = res.read().decode("utf-8")
return json.loads(body)["ip"]
finally:
conn.close()
# ---- 사용 예시 ----
if __name__ == "__main__":
fetcher = IPFetcher(timeout=5, verify_ssl=True)
# 내부 IP 확인
print("내부 IP :", fetcher.get_internal_ip())
# 외부 IP 확인 (urllib)
try:
print("외부 IP (urllib):", fetcher.get_external_ip_urllib())
except Exception as e:
print("urllib 오류:", e)
print("재시도 (verify_ssl=False):", IPFetcher(verify_ssl=False).get_external_ip_urllib())
# 외부 IP 확인 (http.client)
try:
print("외부 IP (http.client):", fetcher.get_external_ip_httpclient())
except Exception as e:
print("http.client 오류:", e)
print("재시도 (verify_ssl=False):", IPFetcher(verify_ssl=False).get_external_ip_httpclient())
이제, 아래 예시처럼 IPFetcher 객체 하나로 내부/외부 IP 조회 기능을 모두 사용할 수 있습니다.
fetcher = IPFetcher(timeout=3, verify_ssl=True)
print(fetcher.get_internal_ip())
print(fetcher.get_external_ip_urllib())
print(fetcher.get_external_ip_httpclient())
반응형
'AI, 클라우드, 문서, 자동화 > 파이썬 요리조리' 카테고리의 다른 글
간단한 Word 자동화 프로그램, 다산 정약용의 유배지에서 보낸 편지 (0) | 2025.09.05 |
---|---|
간단한 번역 프로그램, 파일로 저장하기 (0) | 2025.08.24 |
당황하지 말자, 기억나지 않는 문서 암호/비밀번호 찾기(2) (0) | 2025.08.22 |
당황하지 말자, 기억나지 않는 문서 암호/비밀번호 찾기(1) (0) | 2025.08.22 |