Socket 프로그래밍에 있어서 하나의 소켓이 여러 개의 연결을 동시에 처리하려면 다중화(Multiplexing)가 필요합니다. 이를 위해 파이썬에서는 select
모듈을 제공합니다. select
모듈은 여러 개의 소켓을 감시하고, 읽기 또는 쓰기 이벤트가 발생한 소켓만 처리할 수 있도록 도와줍니다.
이번 포스트에서는 select
모듈을 사용하여 Python으로 소켓 I/O 다중화를 구현하는 방법에 대해 알아보겠습니다.
select
함수 소개
select
함수는 세 개의 리스트를 인자로 받습니다. 이 리스트는 읽기, 쓰기, 예외 이벤트가 발생한 소켓들의 집합입니다. select
함수는 해당 소켓들 중에서 어떤 이벤트가 발생했는지를 알려줍니다.
import select
rlist = [socket1, socket2, ...] # 읽기 이벤트 감시할 소켓 리스트
wlist = [socket3, socket4, ...] # 쓰기 이벤트 감시할 소켓 리스트
xlist = [socket5, socket6, ...] # 예외 이벤트 감시할 소켓 리스트
readable, writable, exceptional = select.select(rlist, wlist, xlist, timeout)
rlist
는 읽기 이벤트를 감시할 소켓들의 리스트입니다. wlist
는 쓰기 이벤트를 감시할 소켓들의 리스트이며, xlist
는 예외 이벤트를 감시할 소켓들의 리스트입니다. timeout
은 select
함수가 블로킹된 상태에서 최대 대기시간을 지정하는 값입니다. timeout
이 0인 경우에는 블로킹되지 않고 바로 반환됩니다.
select
함수는 각 이벤트 종류별로 발생한 소켓들을 반환합니다. 따라서 readable
변수에는 읽기 이벤트가 발생한 소켓 리스트, writable
변수에는 쓰기 이벤트가 발생한 소켓 리스트, exceptional
변수에는 예외 이벤트가 발생한 소켓 리스트가 저장되게 됩니다.
이제 위에서 소개한 select
함수를 사용하여 소켓 I/O 다중화를 구현하는 예제를 살펴보겠습니다.
소켓 I/O 다중화 예제
import select
import socket
# 소켓 생성
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 8000))
server_socket.listen(5)
sockets = [server_socket] # 소켓 리스트
while True:
# select를 사용하여 읽기 이벤트를 감시할 소켓을 선택
readable, writable, exceptional = select.select(sockets, [], [], 0)
for sock in readable:
# 새로운 클라이언트 연결을 처리하는 경우
if sock == server_socket:
client_socket, client_address = server_socket.accept()
sockets.append(client_socket)
# 클라이언트 연결에 대한 데이터 수신
else:
data = sock.recv(4096)
if data:
# 데이터 처리 로직
process_data(data)
else:
# 클라이언트 연결 종료
sock.close()
sockets.remove(sock)
위 예제에서는 server_socket
을 생성하여 클라이언트의 연결을 기다리고 있습니다. select
함수를 사용하여 읽기 이벤트를 감시할 소켓으로 sockets
리스트를 선택합니다. server_socket
객체를 sockets
리스트에 추가하여 새로운 클라이언트 연결을 감지하고, 연결된 클라이언트 소켓에서 데이터를 수신하게 됩니다.
위 예제는 단순한 클라이언트-서버 통신 예제일 뿐이지만, select
함수를 사용하면 여러 개의 소켓을 효율적으로 관리하여 다중 클라이언트를 동시에 처리할 수 있습니다.
이로써 파이썬의 select
모듈을 사용하여 Socket I/O 다중화를 구현하는 방법을 살펴보았습니다. select
함수를 사용하면 소켓 I/O의 성능을 획기적으로 향상시킬 수 있으므로, 다중 클라이언트를 다루는 네트워크 애플리케이션을 개발할 때 유용하게 활용할 수 있습니다.