언제나 그렇듯 python 은 예제 소스코드로 보는 것이 이해하기 쉽다.
import socket import struct s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) addr = ('192.168.101.118', 2123) s.connect(addr) # header magicCode = 1234 pType = 12 pVer = 1 # body userIp = bytes('192.168.3.101', encoding='UTF-8') url = bytes('https://abc.com/def.jsp?param1=test¶m2=ABC', encoding='UTF-8') urlLen = len('https://abc.com/def.jsp?param1=test¶m2=ABC') userId = bytes('yhkim', encoding='UTF-8') userIdLen = len('yhkim') values = (magicCode, pType, pVer, userIp, urlLen, url, userIdLen, userId) fmt = '>I I h 16s I {}s I {}s'.format(urlLen, userIdLen) packer = struct.Struct(fmt) sendData = packer.pack(*values) try: s.sendall(sendData) finally: s.close()
socket 의 첫번째 argument
- socket.AF_INET: IPv4
- socket.AF_INET6: IPv6
- socket.AF_UNIX: UNIX local 통신
socket 의 두번째 argument
- socket.SOCK_DGRAM: UDP
- socket.SOCK_STREAM: TCP
- 등등 (socket.SOCK_RAW, socket.SOCK_SEQPACKET, socket.SOCK_NONBLOCK ....)
인터넷에 보이는 많은 예제들은 단순하게 echo server/client 를 보여주기 때문에
실제 업무에서 사용하기에는 문제(?)가 있다.
실제 업무에서는 보통 프로토콜을 정의해서 사용하기 때문이다.
- header 몇 byte, body 몇 byte, body 에서 첫번째 16byte는 사용자 IP... 뭐 이런식으로
위 예제에서 사용한 프로토콜은 아래와 같다.
header > 매직코드: BIN(4), 프로토콜 타입: UINT(4), 통신버전: UINT(2)
body > 사용자 IP: CHAR(16), URL길이: UINT(4), URL: CHAR(X), 아이디길이: UINT(4), 아이디:CHAR(X)
python 은 바이너리를 쉽게 packing, unpacking 할 수 있는 struct 라는 녀석을 제공한다.
struct 라는 녀석에 대해서는 다음시간에 자세히 알아보기로 하고 일단 쉽게 생각하면 format에 맞춰서 변수들을 담아놓고
한번에 바이너리로 처리할 수 있게 도와주는 녀석이라고 생각하면 될 것 같다...
(다음에 자세히 알아볼 때 ... 이게 아니라면 수정하자..)
struct 에서 사용하는 format 을 C 언어와 비교해서 표로 보면 이렇다.
소스코드에서 사용한 것을 보면 아래와 같다.
>I I h 16s I {}s I {}s'.format(urlLen, userIdLen)
앞에 '>'는 big-endian 을 나타내며 순서대로 포맷팅을 해 주는 것이다.
16s 는 16 byte 문자열을 표현한다.
Java의 ByteBuffer의 allocate 처럼 직관적이며 편하게 사용할 수 있다.
Test용 Client 를 만들 때 python 으로 만들면 이렇게 쉽고 간단하고 간결하게 만들 수 있다.
'IT > Python' 카테고리의 다른 글
Python - 예외 처리 (0) | 2018.09.18 |
---|---|
Python - I/O, File I/O, pickle (0) | 2018.09.10 |
Python - Class (0) | 2018.09.07 |
Python - 자료구조 (0) | 2018.08.30 |
Python - 함수 (0) | 2018.08.27 |