반응형
앞서 봤던 select 모델들은 비동기/봉쇄(blocking) 모델이었지만 이번에 배울
Overlapped 모델(이벤트 기반)은 비동기/비봉쇄(non-blocking)의 응용 모델이다.
Overlpapped IO
overlapped io (비동기 + 논블로킹)
- overlapped 함수를 건다 (wsarecv, wsasend)
- overlapped 함수가 성공했는지 확인 후
- 성공했으면 결과 얻어서 처리
- 실패했으면 사유를 확인
char sendbuffer[100];
wsabuf wsabuf[2];
wsabuf[0].buf = sendbuffer;
wsabuf[0].len = 100;
char sendbuffer2[100];
wsabuf[1].buf = sendbuffer2;
wsabuf[1].len = 100;
scatter-gather
- 패킷을 보낼 때 분산되어 있는 패킷을 연결시켜서 하나의 덩어리로 만들어 보내준다.
WSASend, WSARecv
- 비동기 입출력 소켓
- WSABUF배열의 시작주소 + 개수
- 보내고/받은 바이트 수
- 상세 옵션인데 일단 0
- WSAOVERLAPPED구조체 주소값
- 입출력이 완료되면 os가 호출할 콜백 함수
WSASend 와 WSARecv는 비동기이다 보니 우리가 호출한 시점과 실제로 호출된 시점이 다를 수도 있다.
그렇기 때문에 WSASend나 WSARecv 요청을 하였을 때 가만히 놔두어야 한다.
Overlapped모델 (이벤트 기반) 동작 순서
- 비동기 입출력 지원하는 소켓 생성 + 통지 받기 위한 이벤트 객체 생성
- 비동기 입출력 함수 호출 (1에서 만든 이벤트 객체를 같이 넘겨줌)
- 비동기 작업이 바로 완료되지 않으면, WSA_IO_PENDING오류 코드
- 운영체제는 이벤트 객체를 singaled 상태로 만들어서 완료 상태 알려줌
- WSAWaitForMultipleEvents함수 호출해서 이벤트 객체의 signal 판별
- WSAGetOverlappedResult호출해서 비동기 입출력 결과 확인 및 데이터 처리
WSAGetOverlappedResult
- 비동기 소켓
- 넘겨준 Overlapped구조체
- 전송된 바이트 수
- 비동기 입출력 작업이 끝날때까지 대기할지 선택
- 비동기 입출력 잡업 관련 부가 정보. 거의 사용 안함.
//Server
struct Session
{
SOCKET socket = INVALID_SOCKET;
char recvBuffer[BUFSIZE] = { };
int32 recvBytes = 0;
int32 sendBytes = 0;
WSAOVERLAPPED overlapped = {};
};
.
.
.
while (true)
{
SOCKADDR_IN clientAddr;
int32 addrLen = sizeof(clientAddr);
SOCKET clientSocket;
while (true)
{
clientSocket = ::accept(listenSocket, (SOCKADDR*)&clientAddr, &addrLen);
if (clientSocket != INVALID_SOCKET)
break;
if (::WSAGetLastError() == WSAEWOULDBLOCK)
continue;
//문제 있는 상황
return 0;
}
Session session = Session{ clientSocket };
WSAEVENT wsaEvent = ::WSACreateEvent();
session.overlapped.hEvent = wsaEvent;
cout << "Client Connected!" << endl;
while (true)
{
WSABUF wsaBuf;
wsaBuf.buf = session.recvBuffer;
wsaBuf.len = BUFSIZE;
DWORD recvLen = 0;
DWORD flags = 0;
if (::WSARecv(clientSocket, &wsaBuf, 1, &recvLen, &flags, &session.overlapped, nullptr) == SOCKET_ERROR)
{
if (::WSAGetLastError() == WSA_IO_PENDING)
{
//Pending
::WSAWaitForMultipleEvents(1, &wsaEvent, TRUE, WSA_INFINITE, FALSE);
::WSAGetOverlappedResult(session.socket, &session.overlapped, &recvLen, FALSE, &flags);
}
else
{
//TODO : 문제 있는 상황
break;
}
}
cout << "Data Recv Len = " << recvLen << endl;
}
::closesocket(session.socket);
::WSACloseEvent(wsaEvent);
}
//Client
WSAEVENT wsaEvent = ::WSACreateEvent();
WSAOVERLAPPED overlapped = {};
overlapped.hEvent = wsaEvent;
while (true)
{
WSABUF wsaBuf;
wsaBuf.buf = sendBuffer;
wsaBuf.len = 100;
DWORD sendLen = 0;
DWORD flags = 0;
if (::WSASend(clientSocket, &wsaBuf, 1, &sendLen, flags, &overlapped, nullptr) == INVALID_SOCKET)
{
if (::WSAGetLastError() == WSA_IO_PENDING)
{
//Pending
::WSAWaitForMultipleEvents(1, &wsaEvent, TRUE, WSA_INFINITE, FALSE);
::WSAGetOverlappedResult(clientSocket, &overlapped, &sendLen, FALSE, &flags);
}
else
{
//진짜 문제 있는 상황
break;
}
}
cout << "Send Data! Len = " << sendBuffer << endl;
this_thread::sleep_for(1s);
}
반응형
'네트워크 프로그래밍' 카테고리의 다른 글
IOCP 모델 (0) | 2023.02.24 |
---|---|
Overlapped 모델 (콜백 기반) (0) | 2023.02.24 |
비동기 vs 동기, Blocking vs Non-Blocking (0) | 2023.02.23 |
WSAEventSelect Model (0) | 2023.02.23 |
Select Model (0) | 2023.02.20 |