[파이썬] socket I/O 다중화를 위한 `select` 사용하기

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는 예외 이벤트를 감시할 소켓들의 리스트입니다. timeoutselect 함수가 블로킹된 상태에서 최대 대기시간을 지정하는 값입니다. 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의 성능을 획기적으로 향상시킬 수 있으므로, 다중 클라이언트를 다루는 네트워크 애플리케이션을 개발할 때 유용하게 활용할 수 있습니다.