IOCP란 Input Output Completion Port의 줄임말로 Windos 운영 체제에서 비동기 입출력 작업을 처리하기 위한 메커니즘이다.
IOCP의 핵심 아이디어는 여러 비동기 I/O 작업을 효율적으로 관리하고, 완료된 I/O 작업을 처리하기 위한 스레드 풀을 최적화 하는 것이다.
IOCP는 비동기(Asynchronous) + 스레드 풀링(Thread Pooling) + 논 블로킹(Non-Blocking) + 중첩 입출력(Overlapped I/O)과 같은 개념들을 이용해서 작동한다.
IOCP는 내가 아는 네트워크에서의 Port와는 다른 역할을 하는 것 같은데, 왜 Port라는 이름이 붙었을까?
포트는 운영 체제 통신의 종단점(endpoint)이다. 이 용어는 하드웨어 장치에도 사용되지만, 소프트웨어에서는 네트워크 서비스나 특정 프로세스를 식별하는 논리 단위이다.
네트워크에서 포트는 특정한 종단점(endpoint)를 나타낸다. IP 주소와 함께 사용되어, IP 주소는 호스트를 식별하고, 포트를 통해 해당 호스트 내에서 실행 중인 특정 애플리케이션이나 서비스를 구분한다.
네트워크에서 포트가 통신 지점 역할을 하듯이, 이름에서 "Port"가 사용된 이유는, 비동기 I/O 작업의 완료 결과를 수신하는 지점으로 비유되기 때문이다.
실제 네트워크 포트는 아니지만, 마치 네트워크 포트에서 데이터가 도착하는 것처럼, I/O 작업이 완료될 때 그 결과가 이 "Complete Port"로 수신된다는 의미를 담고 있다.

비동기 I/O 처리의 장점:
예시
OVERLAPPED overlapped = {0};
ReadFile(hFile, buffer, bufferSize, NULL, &overlapped);
// 파일 읽기가 진행되는 동안 다른 작업 수행 가능

스레드 풀 관리의 장점:
IOCP 스레드 풀 생성 예:
HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
// 시스템 코어 수에 맞춰 작업자 스레드 생성
for (int i = 0; i < numberOfCores; i++) {
CreateThread(NULL, 0, WorkerThreadFunction, hCompletionPort, 0, NULL);
}
완료 큐의 작동 방식:
컨텍스트 스위칭 최소화의 이점

CreateIoCompletionPort() 함수를 사용해 IOCP 객체를 생성한다.IOCP 객체 생성 과정
CreateIoCompletionPort()를 호출하여 새로운 IOCP 객체를 생성한다. 첫 번째 인자로 INVALID_HANDLE_VALUE를 전달하면 새로운 Complete Port를 생성한다.IOCP 객체 생성 예제:
HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
핸들 연결 시 고려사항
소켓을 IOCP에 연결하는 예:
SOCKET Socket = accept(listenSocket, NULL, NULL);
CreateIoCompletionPort((HANDLE)Socket, hCompletionPort, (ULONG_PTR)completion, 0);
WSASend, WSARecv와 같은 비동기 I/O 함수를 사용하여 작업한다.비동기 I/O 작업 시작 시 주의사항
OVERLAPPED 구조체를 사용해야 한다.WSA_IO_PENDING)GetQueuedCompletionStatus() 함수를 사용하여 완료된 작업을 처리한다.GetQueuedCompletionStatus()
GetQueuedCompletionStatus() 함수를 호출하면 IOCP에서 완료된 내용을 꺼내 받을 수 있다.GetQueuedCompletionStatus() 함수를 실행하고 있는 스레드는 Waiting Thread Queue에 쌓인다.I/O 완료 처리 과정:
GetQueuedCompletionStatus() 함수를 호출하여 I/O 작업이 완료되는 것을 기다린다.OVERLAPPED 구조체의 포인터가 반환된다.비동기 작업을 관리하기 위해 OVERLAPPED 구조체를 사용해야 한다고 했다.
OVERLAPPED 구조체가 뭘까?? 간단하게만 알아보겠습니다.
I/O 작업을 요청한 후 작업이 완료될 때까지 해당 스레드가 블로킹되지 않고 다른 작업을 수행할 수 있는 모델
본격적으로 Overlapped IO를 살펴보기 전에 먼저 Blocking과 Non-Blocking에 대해 알아보겠습니다.
기본적으로 I/O 작업은 동기로 이루어진다. 예를 들어 ReadFile(파일을 읽어 들이는 메서드) 함수를 호출 시 읽기 작업이 끝나기 전까지 함수는 값을 반환하지 않고 처리를 기다리게 된다.
이렇게 해당 스레드에서 작업이 끝날 때까지 다른 작업을 수행하지 못하고 대기해야 하는 상태를 블로킹(Blocking) 모드라고 한다.
반대로 Non-Blocking 모드는 I/O 작업을 호출하고 바로 반환되기에 해당 스레드는 I/O 작업을 대기하지 않고 다른 작업을 수행할 수 있다.
동작 방식
Overlapped I/O에서 I/O 작업의 완료 여부를 확인하는 방법은 주로 두 가지 방식이 있다.
1. 이벤트 객체(Event Object)
WaitForSingleObject 또는 WaitForMultipleObjects 등의 함수로 이벤트 객체의 신호 상태를 확인하여, I/O 작업이 완료되었는지 판단한다.2. IOCP
IOCP는 작업자 스레드가 완료포트의 알림을 받아 비동기 작업을 처리하는 방식으로 동작한다. 이러한 IOCP의 특징은 대규모 서버 애플리케이션에서 높은 성능과 효율성을 제공하며, 동시에 많은 클라이언트 요청을 처리하는 데 최적화된 환경을 제공한다.