1. Overlapped I/O란 무엇인가?

기본 개념

  • Overlapped I/O비동기(Asynchronous) I/O 모델로서, I/O 작업이 완료될 때까지 기다리지 않고(논블로킹), 다른 작업을 수행할 수 있도록 설계된 방식입니다.
  • Windows에서는 WSASend, WSARecv와 같은 비동기 함수와 함께 OVERLAPPED 구조체를 사용해 구현됩니다.

2. Overlapped I/O의 주요 특징

  1. 비동기 I/O 지원:
    작업이 완료될 때까지 기다리지 않고 다른 작업을 수행할 수 있습니다.
  2. 논블로킹 방식:
    I/O 함수 호출 즉시 반환되며, 작업이 백그라운드에서 비동기적으로 처리됩니다.
  3. 결과 알림:
    작업 완료 여부를 알리기 위해 이벤트 객체(Event), 콜백(Completion Routine), 또는 IOCP(I/O Completion Port) 중 하나를 사용합니다.

3. Overlapped I/O의 핵심 구성 요소

  1. OVERLAPPED 구조체:
    I/O 작업 상태를 저장하고 관리하는 데 사용됩니다.

    typedef struct _OVERLAPPED {
        ULONG_PTR Internal;       // I/O 작업 상태(내부용)
        ULONG_PTR InternalHigh;   // 완료된 바이트 수 저장
        DWORD Offset;             // 파일 작업 시작 위치 (하위 32비트)
        DWORD OffsetHigh;         // 파일 작업 시작 위치 (상위 32비트)
        HANDLE hEvent;            // 이벤트 객체 핸들
    } OVERLAPPED, *LPOVERLAPPED;
  2. WSABUF 구조체:
    데이터를 송수신할 버퍼의 위치와 크기를 나타내는 구조체입니다.

    typedef struct _WSABUF {
        ULONG len;   // 버퍼의 크기
        CHAR* buf;   // 버퍼의 주소
    } WSABUF, *LPWSABUF;
  3. 이벤트 객체 (Event Object):
    비동기 작업이 완료되면 해당 이벤트 객체를 Signaled 상태로 변경해 알립니다.

  4. 콜백 함수 (Completion Routine):
    작업이 완료되면 운영체제가 자동으로 호출하는 함수입니다.

  5. Alertable Wait 상태:
    스레드를 특별한 대기 상태로 전환하여 콜백 함수 실행을 대기합니다.


4. Overlapped I/O 처리 절차

1단계: 비동기 소켓 설정

  • 소켓을 논블로킹으로 설정합니다.
    u_long on = 1;
    ioctlsocket(socket, FIONBIO, &on);

2단계: 이벤트 객체 생성

  • 이벤트 객체를 생성해 OVERLAPPED 구조체와 연동합니다.
    WSAEVENT event = WSACreateEvent();
    OVERLAPPED overlapped = {};
    overlapped.hEvent = event;

3단계: 비동기 I/O 함수 호출

  • WSARecvWSASend 같은 함수를 사용해 I/O 작업을 요청합니다.

    • WSA_IO_PENDING: 작업이 아직 완료되지 않았음을 의미.
    WSABUF buf;
    buf.buf = session.recvBuffer;
    buf.len = BUFSIZE;
    
    DWORD bytesTransferred = 0;
    DWORD flags = 0;
    
    if (WSARecv(socket, &buf, 1, &bytesTransferred, &flags, &overlapped, RecvCallback) == SOCKET_ERROR) {
        if (WSAGetLastError() == WSA_IO_PENDING) {
            // 작업이 완료되지 않았으므로 이벤트 대기
        }
    }

4단계: 작업 완료 대기 및 확인

  1. 이벤트 기반:

    • WSAWaitForMultipleEvents 함수를 사용해 이벤트 객체의 상태를 감시합니다.
      WSAWaitForMultipleEvents(1, &event, TRUE, WSA_INFINITE, FALSE);
      WSAGetOverlappedResult(socket, &overlapped, &bytesTransferred, FALSE, &flags);
  2. 콜백 기반:

    • 콜백 함수(RecvCallback)가 작업 완료 시 호출됩니다.
      void CALLBACK RecvCallback(DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags) {
          Session* session = (Session*)overlapped;
          cout << "Received Data: " << session->recvBuffer << endl;
      }

5. Overlapped I/O 코드 분석

아래는 Overlapped 모델을 사용한 예제 코드입니다. 각 부분을 상세히 분석하겠습니다.

코드 예제

// 1. 클라이언트 소켓 설정
SOCKET clientSocket = accept(listenSocket, (SOCKADDR*)&clientAddr, &addrLen);
WSAEVENT wsaEvent = WSACreateEvent(); // 이벤트 객체 생성

// 2. Overlapped 구조체 초기화
OVERLAPPED overlapped = {};
overlapped.hEvent = wsaEvent;

// 3. 비동기 수신 함수 호출
WSABUF wsaBuf;
wsaBuf.buf = recvBuffer;
wsaBuf.len = BUFSIZE;

DWORD recvLen = 0;
DWORD flags = 0;

if (WSARecv(clientSocket, &wsaBuf, 1, &recvLen, &flags, &overlapped, RecvCallback) == SOCKET_ERROR) {
    if (WSAGetLastError() == WSA_IO_PENDING) {
        // 4. Alertable Wait 상태로 대기
        SleepEx(INFINITE, TRUE);
    }
}

// 5. 작업 완료 시 RecvCallback 호출
void CALLBACK RecvCallback(DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags) {
    cout << "Data Received: " << bytesTransferred << " bytes" << endl;
}

코드 상세 분석

  1. 이벤트 객체 생성 및 Overlapped 초기화:

    • 이벤트 객체는 작업 완료 여부를 확인하는 데 사용됩니다.
    WSAEVENT wsaEvent = WSACreateEvent();
    OVERLAPPED overlapped = {};
    overlapped.hEvent = wsaEvent;
  2. WSARecv 호출:

    • WSARecv 함수는 데이터를 비동기적으로 수신합니다.
    • 결과는 콜백 함수로 전달됩니다.
    if (WSARecv(...) == SOCKET_ERROR) {
        if (WSAGetLastError() == WSA_IO_PENDING) {
            SleepEx(INFINITE, TRUE);
        }
    }
  3. Alertable Wait:

    • SleepEx 함수는 스레드를 Alertable 상태로 만들어 콜백 함수를 실행합니다.
  4. 콜백 함수:

    • 작업이 완료되면 운영체제가 RecvCallback을 호출합니다.
    void CALLBACK RecvCallback(...) {
        cout << "Data Received: " << bytesTransferred << " bytes" << endl;
    }

6. Overlapped I/O의 장단점

장점:

  • 비동기 작업으로 대기 시간을 최소화.
  • 이벤트 또는 콜백을 통해 효율적으로 작업 완료 처리.
  • CPU 활용도를 극대화하여 고성능 서버 구현 가능.

단점:

  • 구현의 복잡성: 코드가 복잡하고 디버깅이 어려움.
  • 성능 저하: 빈번한 Alertable Wait 상태는 성능 저하를 일으킬 수 있음.
  • 제한 사항: 일부 함수(예: accept)는 콜백 기반으로 동작하지 않음.

profile
李家네_공부방

0개의 댓글