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)
서버 소스는 아래와 같습니다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import socket | |
port = 9999 | |
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
host = '127.0.0.1' | |
s.bind((host, port)) | |
s.listen(5) | |
print "listen ok" | |
while True: | |
c, addr= s.accept() | |
print 'connection', addr | |
c.send('Connection success') | |
c.close() |
먼저 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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import socket | |
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
host = '127.0.0.1' | |
port = 9999 | |
s.connect((host, port)) | |
print s.recv(1024) | |
s.close() |
그리고 아래와 같이 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
-----------------------------------------------------