Python 표준 라이브러리의 socket 모듈은 운영체제 위에서 서버와 클라이언트가 소켓 엔드포인트를 통해 통신하는 방법을 정의합니다. 이 API는 연결 지향형 프로토콜과 비연결형 프로토콜을 모두 지원하는 함수들을 제공합니다.
소켓(Socket)은 양방향 통신 링크의 끝점(end-point)입니다. 각 소켓은 IP 주소와 포트 번호로 식별되며, 통신을 시작하려면 양쪽 끝에서 소켓이 올바르게 설정되어야 합니다. 이를 통해 클라이언트-서버 환경에서 들어오는 메시지를 수신하고 응답을 보낼 수 있습니다.
소켓 객체 생성하기
socket 모듈의 socket() 함수를 사용하면 소켓 객체를 생성할 수 있습니다.
import socket
obj = socket.socket(family, type, protocol)
각 인자의 의미는 다음과 같습니다.
- family: 기본값은
AF_INET이며, 그 외에AF_INET6(IPv6),AF_UNIX(유닉스 도메인),AF_CAN,AF_RDS등을 사용할 수 있습니다. - type: 기본값은
SOCK_STREAM으로 연결 지향형 프로토콜(TCP)을 의미합니다. 비연결형 프로토콜(UDP)을 사용하려면SOCK_DGRAM으로 설정합니다. - protocol: 일반적으로 기본값인 0을 사용합니다.
서버 측 소켓 객체를 서버 소켓(server socket), 클라이언트 측 소켓 객체를 클라이언트 소켓(client socket)이라고 부릅니다.
서버 소켓의 주요 메서드
| bind() | 소켓을 지정된 IP 주소와 포트 번호에 바인딩(연결)합니다. |
| listen() | 서버를 시작하고, 클라이언트의 연결 요청을 기다리는 대기 루프에 진입합니다. |
| accept() | 서버가 연결 요청을 받으면 이를 수락하고, 클라이언트 소켓과 해당 주소를 반환합니다. |
전형적인 서버 측 코드는 다음과 같습니다.
import socket
ss = socket.socket()
ss.bind(('localhost', 12345))
ss.listen()
client, addr = ss.accept()
print("connection request from: " + str(addr))
같은 머신에서 서버와 클라이언트를 함께 실행하는 경우 IP 주소는 127.0.0.1을 사용합니다. 이 주소를 루프백(loopback) 주소라고 하며, 호스트명으로는 localhost로 식별됩니다. 포트는 임의의 비어 있는 번호를 지정하면 되지만, 네트워크상의 원격 머신 간 통신에는 실제 IP 주소를 사용해야 합니다.
connect(): 클라이언트의 연결 요청
클라이언트 소켓은 서버가 대기 중인 IP 주소와 포트 번호로 연결 요청을 보냅니다.
obj = socket.socket()
obj.connect((host, port))
서버가 클라이언트의 연결 요청을 수락하면 두 소켓 객체는 TCP 프로토콜로 연결되어 데이터를 주고받을 수 있게 됩니다.
send(): 데이터 전송
서버는 accept()로 확인한 주소를 통해 클라이언트에 데이터를 전송합니다.
client.send(bytes)
클라이언트 소켓은 연결이 established된 상대 소켓으로 데이터를 전송합니다.
obj.send(bytes)
sendall()
send()와 유사하지만, 전달한 데이터가 모두 전송될 때까지 계속해서 전송을 시도한다는 점이 다릅니다.
sendto()
UDP 프로토콜에서만 사용하는 메서드로, 목적지 주소를 명시하여 데이터를 전송합니다.
recv(): 데이터 수신
상대방이 보낸 데이터를 가져올 때 사용합니다. 서버의 경우 연결 요청을 수락한 원격 소켓을 통해 데이터를 수신합니다.
client.recv(bytes)
클라이언트의 경우 다음과 같습니다.
obj.recv(bytes)
recvfrom()
UDP 프로토콜에서 사용되는 메서드로, 데이터와 함께 송신자의 주소 정보도 함께 반환합니다.
전체 예제 코드
서버 코드
import socket
host = "127.0.0.1"
port = 12345
ss = socket.socket()
ss.bind((host, port))
ss.listen()
cs, addr = ss.accept()
print("Connection from: " + str(addr))
while True:
data = cs.recv(1024).decode()
if not data:
break
print("from connected user: " + str(data))
reply = input("type message: ")
cs.send(reply.encode())
cs.close()
클라이언트 코드
import socket
host = '127.0.0.1'
port = 12345
obj = socket.socket()
obj.connect((host, port))
message = input("type message: ")
while message != 'q':
obj.send(message.encode())
data = obj.recv(1024).decode()
print('Received from server: ' + data)
message = input("type message: ")
obj.close()
실행 방법
명령 프롬프트 창을 두 개 열고, 한쪽에서는 먼저 서버 코드를 실행합니다. 그다음 다른 창에서 클라이언트 코드를 실행하면 두 프로세스 간에 메시지를 주고받는 것을 확인할 수 있습니다.