IOCP 기본 구조
왜 공부했나
게임 서버에서 수천 명의 동시 접속을 처리해야 하는데, 스레드-퍼-클라이언트 방식으로는 스레드 컨텍스트 스위칭 비용이 너무 커진다. Windows에서 이를 해결하는 표준 방법이 IOCP라서 공부 시작.
핵심 개념
IOCP란
OS 커널이 I/O 완료 이벤트를 큐에 쌓아주면, 워커 스레드 풀이 꺼내서 처리하는 구조. 스레드 수를 CPU 코어 수 × 2 정도로 고정해도 수천 소켓을 처리할 수 있다.
[클라이언트들]
↓ (WSARecv 등록)
[IOCP 완료 큐] ← OS 커널이 I/O 완료 시 자동 적재
↓ (GetQueuedCompletionStatus)
[워커 스레드 풀] ← 고정된 수의 스레드만 사용핵심 함수 3개
| 함수 | 역할 |
|---|---|
CreateIoCompletionPort |
IOCP 핸들 생성 + 소켓 연결 |
WSARecv / WSASend |
비동기 I/O 요청 등록 |
GetQueuedCompletionStatus |
완료 이벤트 꺼내기 (블로킹) |
코드 예제
// 1. IOCP 핸들 생성
HANDLE hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
// 2. 소켓을 IOCP에 연결
CreateIoCompletionPort((HANDLE)clientSocket, hIocp, (ULONG_PTR)pSession, 0);
// 3. 비동기 수신 등록
WSABUF wsaBuf = { BUF_SIZE, pSession->recvBuf };
DWORD flags = 0;
WSARecv(clientSocket, &wsaBuf, 1, nullptr, &flags, &pSession->overlapped, nullptr);
// 4. 워커 스레드에서 완료 이벤트 처리
DWORD transferred;
ULONG_PTR key;
OVERLAPPED* pOverlapped;
GetQueuedCompletionStatus(hIocp, &transferred, &key, &pOverlapped, INFINITE);막혔던 부분 / 삽질
OVERLAPPED구조체를 스택에 두면 비동기 완료 전에 사라져서 크래시 발생 → 반드시 힙 또는 세션 객체 멤버로 관리해야 함GetQueuedCompletionStatus가FALSE를 반환해도transferred == 0이면 정상 종료, 그 외는 에러 — 이 분기를 놓치면 좀비 세션 생김
정리
- IOCP = OS가 관리하는 완료 이벤트 큐 + 고정 워커 스레드
- 핵심은
OVERLAPPED수명 관리 — 비동기 작업이 끝날 때까지 살아있어야 함 - 다음: Per-IO 데이터 확장 구조 로 세션 정보를 OVERLAPPED에 붙이는 방법