쓸툴.site
Tech & Story

Flask-SocketIO로 구현한 실시간 멀티플레이어 게임: HTTP의 한계를 넘어서

📅 2025-12-14 👨‍💻 에디터 K
Flask-SocketIO로 구현한 실시간 멀티플레이어 게임: HTTP의 한계를 넘어서

웹 개발을 하다 보면 '새로고침'의 굴레에 갇힐 때가 있습니다. 게시판이나 블로그라면 상관없지만, 실시간으로 진행되는 야추(Yacht) 게임이나 오목 같은 멀티플레이어 게임에서는 치명적입니다. 상대방이 돌을 뒀는데 내 화면에는 1분 뒤에 뜬다면 게임이 성립될 수 없으니까요.

초기에는 클라이언트가 1초마다 서버에 "새 데이터 있어?"라고 묻는 폴링(Polling) 방식을 고려했습니다. 하지만 이는 서버에 불필요한 트래픽 폭탄을 던지는 꼴이었습니다. 그래서 저는 WebSocket 기술을 도입하기로 결정했습니다. Flask 환경에서 소켓 통신을 가장 우아하게 처리해 주는 Flask-SocketIO 라이브러리 적용기를 소개합니다.

1. 연결의 지속성: Handshake부터 Event Emit까지

HTTP는 '요청-응답'이 끝나면 연결을 끊어버리는 비연결성(Stateless) 프로토콜입니다. 반면 웹소켓은 한 번 연결되면(Handshake) 빨대처럼 통로가 유지됩니다. 서버는 클라이언트의 요청이 없어도 언제든 데이터를 '밀어 넣을(Push)' 수 있습니다.

이를 통해 상대방이 주사위를 굴리자마자 socket.emit('roll_result', ...) 이벤트가 발생하고, 내 화면의 주사위가 즉시 굴러가는 마법 같은 사용자 경험(UX)을 구현할 수 있었습니다. 반응 속도는 밀리초(ms) 단위로 줄어들었고, 서버 부하는 획기적으로 감소했습니다.

2. 룸(Room) 기능을 활용한 게임 세션 격리

동시 접속자가 100명이라면 어떻게 해야 할까요? 모든 사람의 게임 현황을 서로에게 보낼 수는 없습니다. 여기서 SocketIO의 강력한 기능인 '룸(Room)'이 빛을 발합니다.

join_room(room_id) 함수를 사용해 특정 게임 방에 입장한 유저들끼리만 묶어주면, 서버는 emit(..., room=room_id) 한 줄로 해당 방의 인원에게만 데이터를 전송할 수 있습니다. 이를 통해 A방에서는 오목을 두고, B방에서는 야추를 해도 서로 간섭이 전혀 없는 완벽한 멀티플레이 환경을 구축했습니다.

3. 비동기(Async) 라이브러리 eventlet의 역할

파이썬의 Flask는 기본적으로 동기(Synchronous) 방식이라 소켓 처리에 한계가 있습니다. 수천 개의 연결을 동시에 유지하려면 비동기 네트워킹 라이브러리가 필수입니다. 저는 eventlet을 WSGI 서버로 사용하여 동시성(Concurrency) 문제를 해결했습니다.

배포 과정에서 gunicorn -k eventlet ... 옵션을 주어 실행함으로써, 단일 스레드에서도 수많은 소켓 연결을 넌블로킹(Non-blocking)으로 처리할 수 있게 되었습니다. 실시간 서비스를 기획 중이라면 비동기 처리에 대한 이해는 필수입니다.

⚡ 실시간 웹의 매력

정적인 웹 페이지에 생명을 불어넣고 싶다면 소켓 통신에 도전해 보세요. 사용자의 클릭 하나하나가 서버를 거쳐 타인의 화면을 움직이는 것을 보는 건 개발자로서 느낄 수 있는 최고의 희열 중 하나입니다.

웹소켓 기술이 적용된 실시간 대전을 체험해보세요!

🎲 야추 다이스(Yacht) 멀티플레이 하기

이 글이 도움이 되셨나요?

친구들에게 공유하고 함께 이야기해보세요!

🤖