WSASend, WSARecv와 같은 비동기 함수와 함께 OVERLAPPED 구조체를 사용해 구현됩니다.OVERLAPPED 구조체:
I/O 작업 상태를 저장하고 관리하는 데 사용됩니다.
typedef struct _OVERLAPPED {
ULONG_PTR Internal; // I/O 작업 상태(내부용)
ULONG_PTR InternalHigh; // 완료된 바이트 수 저장
DWORD Offset; // 파일 작업 시작 위치 (하위 32비트)
DWORD OffsetHigh; // 파일 작업 시작 위치 (상위 32비트)
HANDLE hEvent; // 이벤트 객체 핸들
} OVERLAPPED, *LPOVERLAPPED;
WSABUF 구조체:
데이터를 송수신할 버퍼의 위치와 크기를 나타내는 구조체입니다.
typedef struct _WSABUF {
ULONG len; // 버퍼의 크기
CHAR* buf; // 버퍼의 주소
} WSABUF, *LPWSABUF;
이벤트 객체 (Event Object):
비동기 작업이 완료되면 해당 이벤트 객체를 Signaled 상태로 변경해 알립니다.
콜백 함수 (Completion Routine):
작업이 완료되면 운영체제가 자동으로 호출하는 함수입니다.
Alertable Wait 상태:
스레드를 특별한 대기 상태로 전환하여 콜백 함수 실행을 대기합니다.
u_long on = 1;
ioctlsocket(socket, FIONBIO, &on);OVERLAPPED 구조체와 연동합니다.WSAEVENT event = WSACreateEvent();
OVERLAPPED overlapped = {};
overlapped.hEvent = event;WSARecv나 WSASend 같은 함수를 사용해 I/O 작업을 요청합니다.
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) {
// 작업이 완료되지 않았으므로 이벤트 대기
}
}
이벤트 기반:
WSAWaitForMultipleEvents 함수를 사용해 이벤트 객체의 상태를 감시합니다.WSAWaitForMultipleEvents(1, &event, TRUE, WSA_INFINITE, FALSE);
WSAGetOverlappedResult(socket, &overlapped, &bytesTransferred, FALSE, &flags);콜백 기반:
RecvCallback)가 작업 완료 시 호출됩니다. void CALLBACK RecvCallback(DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags) {
Session* session = (Session*)overlapped;
cout << "Received Data: " << session->recvBuffer << endl;
}아래는 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;
}
이벤트 객체 생성 및 Overlapped 초기화:
WSAEVENT wsaEvent = WSACreateEvent();
OVERLAPPED overlapped = {};
overlapped.hEvent = wsaEvent;
WSARecv 호출:
WSARecv 함수는 데이터를 비동기적으로 수신합니다.if (WSARecv(...) == SOCKET_ERROR) {
if (WSAGetLastError() == WSA_IO_PENDING) {
SleepEx(INFINITE, TRUE);
}
}
Alertable Wait:
SleepEx 함수는 스레드를 Alertable 상태로 만들어 콜백 함수를 실행합니다.콜백 함수:
RecvCallback을 호출합니다.void CALLBACK RecvCallback(...) {
cout << "Data Received: " << bytesTransferred << " bytes" << endl;
}
accept)는 콜백 기반으로 동작하지 않음.