파이썬 소켓 모듈(socket)
목차
호스트 컴퓨터 이름과 아이피 이름
파이썬 소켓(socket) 모듈의 socket 클래스를 통해서 알아낼 수 있습니다. 아래의 gethostname 은 로컬호스트의 이름을 리턴하고 gethostbyname 은 컴퓨터의 이름이나 도메인이름을 사용하여 ip 를 가져올 수 있습니다.
윈도우의 경우 명령프롬프트에서 ipconfig 를 하면 IPv4 주소를 볼 수 있습니다.
import socket hostName = socket.gethostname() ipAdress = socket.gethostbyname(hostName) print(hostName) print(ipAdress)
DESKTOP 127.0.0.1
도메인 이름을 사용하면 먼 곳에 있는 컴퓨터의 정보를 가져오는 것도 가능합니다.
파이썬 홈페이지의 ip 주소를 가져와보겠습니다.
import socket remoteHost = 'www.python.org' ipAdress = socket.gethostbyname(remoteHost) print(remoteHost) print(ipAdress)
www.python.org 151.101.228.223
IP주소는 고정아이피가 아닌 경우 바뀔 수 있습니다.
IP 패킹과 언패킹
IP 주소는 문자열의 형태를 가지고 있으므로 네트워크상 전송하기엔 좋지 않습니다.
따라서 네트워크로 데이터를 전송하기 전에 IP주소를 바이트로 바꿔주는 패킹을 하고 도착했을 때는 데이터의 언패킹이 필요합니다. 여기서는 IP주소를 32bit 변환을 했습니다.
b’9765e4df’ 이게 16진수인데 하나가 4바이트 표현입니다. 두개씩 모아서 10진수로 바꾸면 IP주소와 같습니다.
약간 귀찮지만 네트워크 전송을 위한 변환과정을 거친다고 생각하면 됩니다. 택배로 물건을 보낼 때 포장하는 과정과 비슷합니다.
import socket from binascii import hexlify remoteHost = 'www.python.org' ipAdress = socket.gethostbyname(remoteHost) print('host :', remoteHost) print('IP address:', ipAdress) packedIpAddr = socket.inet_aton(ipAdress) print('packed IP:', hexlify(packedIpAddr)) unpackedIpAddr = socket.inet_ntoa(packedIpAddr) print('unpacked IP:',unpackedIpAddr)
host : www.python.org IP address: 151.101.228.223 packed IP: b'9765e4df' unpacked IP: 151.101.228.223
포트번호에서 서비스 이름 확인
로컬호스트의 포트번호와 프로토콜에 있는 서비스를 찾을 수 있습니다.
프로토콜 두개 tcp와 udp 를 사용해서 돌려봤습니다.
protocol = 'tcp' for portNum in range(99): try: print(portNum, ":" ,socket.getservbyport(portNum, protocol)) except: print(end='')
tcp 서비스
7 : echo 9 : discard 11 : systat 13 : daytime 17 : qotd 19 : chargen 20 : ftp-data 21 : ftp 22 : ssh 23 : telnet 25 : smtp 37 : time 42 : nameserver 43 : nicname 53 : domain 70 : gopher 79 : finger 80 : http 81 : hosts2-ns 88 : kerberos
udp 서비스
7 : echo 9 : discard 11 : systat 13 : daytime 17 : qotd 19 : chargen 37 : time 39 : rlp 42 : nameserver 53 : domain 67 : bootps 68 : bootpc 69 : tftp 81 : hosts2-ns 88 : kerberos
거의 비슷합니다. tcp 에 ftp, http 가 있고 udp에 tftp 가 보입니다. 왼쪽의 번호는 포트번호입니다.
네트워크 바이트와 호스트 바이트 변환
다음은 네트워크 바이트와 호스트 바이트를 변환하는 함수입니다. ntohl 에서 n 은 network to h 는 host l 은 long 의 약어입니다.
myData = 1234 netLong = socket.ntohl(myData) hostLong = socket.htonl(myData) print('network byte:', netLong) print('host byte :', hostLong)
network byte: 3523477504 host byte : 3523477504
소켓타임아웃 설정
소켓타임아웃을 설정할 수 있습니다. 단위는 1초입니다.
아래의 코드는 소켓을 생성합니다. s1 은 소켓 객체입니다. 객체에 있는 타임아웃 정보를 바꿀 수 있습니다.
import socket s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print("default socket timeout:", s1.gettimeout()) s1.settimeout(200) print("current socket timeout:", s1.gettimeout())
default socket timeout: None current socket timeout: 200.0
소켓 버퍼사이즈
기본 버퍼사이즈를 변경합니다. 운영체제의 상황에 따라 버퍼 사이즈가 다를 수 있습니다.
import socket SEND_BUF_SIZE = 4096 RECV_BUF_SIZE = 4096 def modify_buff_size(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM ) bufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF) print("Buffer size [Before]:%d" %bufsize) sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) sock.setsockopt( socket.SOL_SOCKET, socket.SO_SNDBUF, SEND_BUF_SIZE) sock.setsockopt( socket.SOL_SOCKET, socket.SO_RCVBUF, RECV_BUF_SIZE) bufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF) print("Buffer size [After]:%d" % bufsize) modify_buff_size()
Buffer size [Before]:65536 Buffer size [After]:4096
파이썬 소켓 모듈 요약
파이썬 소켓 모듈은 네트워크 프로그래밍을 쉽게 하기 위해 OSI 7 단계를 추상화 시켜 놓았습니다. 파이썬에는 네트워크를 다루기 위해 socket 모듈 외에 scapy 등 저수준에서 네트워크를 조작할 수 있는 다양한 모듈이 구비되어 있습니다.
이 모든 기능들을 PYPI 를 통해 손쉽게 다운로드 받을 수 있는데 이 때문에 파이썬으로 하는 네트워크 프로그램과 해킹방법도 계속 발전하고 있습니다.
파이썬을 통한 네트워크 프로그래밍의 학습은 파이썬 학습의 난이도에도 중급 단계에 속합니다. 파이썬 기초 프로그래밍은 코드를 따라해보는 것 만으로도 빠르게 진도를 나갈 수 있습니다. 그러나 네트워크 프로그래밍의 경우 컴퓨터 네트워크의 구조와 서버 클라이언트 모델에 대한 배경 이론을 학습해야 이해할 수 있는 부분이 있습니다.
한편으로는 네트워크를 다루기 때문에 훨씬 재미있죠. 한편 최근의 프로그래밍 환경에서 네트워크를 다루지 못하면 아무리 좋은 프로그램이라도 반쪽짜리 입니다.
파이썬에는 소켓 프로그래밍 뿐 아니라 웹스크래핑 등 다양한 네트워킹 기술이 있습니다. 앞으로 스무디코딩에서는 파이썬의 다양한 프로그래밍 코드와 기법을 소개할 예정입니다.
파이썬에 관심이 있는 분들은 꼭 한번 도전해보시길 바랍니다.
외부참조링크
socket — 저수준 네트워킹 인터페이스 — Python 3.9.1 문서