Socket의 선언은 아래와 같습니다.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
여기서 각각 PF(프로토콜 체계)와 AF(주소 체계)를 살펴보면
A. PF
- PF_INET - IPv4 프로토콜
- PF_INET6 - IPv6 프로토콜
- PF_LOCAL - Local 통신 UNIX 프로토콜
B. AF
- AF_INET - IPv4 프로토콜
- AF_INET6 - IPv6 프로토콜
- AF_LOCAL - Local 통신 UNIX 프로토콜
이를 통해 소켓을 만들 때에 사용하고자 하는 프로토콜을 사용할땐 PF를 주소 구조체 안에 주소 체계를 정의할 때엔 AF를 사용합니다.
기본적으로 C에서 socket을 생성 할 때 PF_INET을 사용하지만, Python에는 PF가 없습니다.
그리고 뒤에오는 SOCK_STREAM과 SOCK_DGRAM을 통해 각 각 TCP UDP를 결정하게 됩니다.
Socket에 대한 binding은 아래와 같이 선언합니다.
s.bind((host, port))
위와 같이 소켓 선언과 바인딩이 타 언어에 비해 아주 심플한 모습을 취하고 있습니다.
소켓을 통해 간단하게 값을 한 번만 주고 받는 에코서버를 작성해보도록 하겠습니다.
1. Server
서버에서 원격지의 소켓을 받기 위한 listen은 아래와 같이 선언합니다. 이 부분은 C의 서버 프로그래밍과 유사합니다.
s.listen(5)
listen을 통해 소켓이 개통이 되는데 뒤의 인자 backlog는 커널이 관리하는 대기 큐에서
연결 요청을 하고 기다리는 총 클라이언트의 수 입니다.
위 큐에 연결 요청한 소켓은 SYN_RCVD나 ESTABLISHED 상태로 대기합니다. 이 함수를 호
출하면 커널은 내부적으로 소켓의 상태를 CLOSED에서 LISTEN으로 바꿔줍니다.
Status
- SYN_RCVD - 클라이언트가 connect 함수로 서버에 요청한 연결을 처리하기 위해 SYN 패킷을 통한 3-Way Handshaking을 진행하는 중입니다.
- ESTABLISHED - 3-Way Handshaking이 모두 완료되면 이 상태가 됩니다.
마지막으로 클라이언트의 연결을 위한 accept 함수는 아래와 같습니다.
c = s.accept()
위를통해 클라이언트 소켓을 Accept 할 수 있습니다.
이제 send와 recv를 통해 값을 주고 받을 수 있습니다.
socket.send("connect success")
socket.recv(1024)
서버 소스는 아래와 같습니다.
먼저 socket.socket()를 통해 소켓을 생성 한 뒤
9999번 포트의 루프백 ip 127.0.0.1로 bind 해줍니다.
s.listen(5)와 s.accept()를 통해 클라이언트 소켓을 연결 한 뒤
send를 통해 'Connection success'를 전송 해 줍니다.
클라이언트가 들어오기 전 c, addr = s.accept()에서 대기중인 실행 모습은 아래와 같습니다.
listen ok
2. Client
Client 또한 마찬가지로 socket.socket()를 통해 소켓을 생성 해 줍니다.
그리고 아래와 같이 connect() 함수를 통해 해당 ip 127.0.0.1과 9999번 포트에 소켓을 연결 해 줍니다.
s.connect((host, port))
그리고 recv를 통해 상대방의 send를 기다립니다.
s.recv(1024)
서버와 클라이언트의 실행 결과는 아래와 같습니다.
-----------------------Server-----------------------
listen ok
connection ('127.0.0.1', 2617)
-----------------------Client------------------------
Connection success
-----------------------------------------------------