21-1. Overlapped 입출력의 의미
비중첩 데이터 입출력 모델
중첩된 데이터 입출력 모델
하나의 쓰레드 내에서 여러 개의 입출력이 진행되는 것
21-2. Overlapped 입출력을 위한 기본 단계
1. Overlapped 소켓의 생성
SOCKET WSASocket(
__in int af,
__in int type,
__in int protocol,
__in LPWSAPROTOCOL_INFO lpProtocolInfo,
__in GROUP g,
__in DWORD dwFlags
);
af : address family
type : 소켓 형태
protocol : 사용된 프로토콜(여기까지 socket과 동일)
lpProtocolInfo : 생성될 소켓의 성경을 정의하는 wSAPROTOCOL_INFO 포인터
g : 예약됨.
dwFlags : 소켓 속성을 지정하는 플래그
WSASocket(PF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
WSA_FLAG_OVERLAPPED는 Overlapped 입출력이 가능하도록 하는 플래그.
2. 데이터 송수신
※ 다음 함수들은 버퍼에 존재하는 데이터를 모아서 한 번에 전송하고(Gather) 수신된 데이터를 여러 버퍼에 나누어 저장(Scatter)하는 Gather/Scatter 입출력을 한다.
int WSASend(
SOCKET s, // 소켓 핸들
LPWSABUF lpBuffers, // WSABUF 구조체 배열의 포인터
DWORD dwBufferCount, // lpBuffers가 가리키는 배열의 크기
LPDWORD lpNumberOfBytesSent, // 전송된 바이트 수를 저장하기 위한 포인터
DWORD dwFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTING lpCompletionRoutine
);
리턴 : 성공시 0, 실패시 SOCKET_ERROR
typedef struct __WSABUF{
u_long len;
char FAR *buf;
}WSABUF, FAR* LPWSABUF;
int WSARecv(
SOCKET s, // 소켓 핸들
LPWSABUF lpBuffers, // 수신 버퍼 정보를 지니는WSABUF 구조체 배열의 포인터
DWORD dwBufferCount, // lpBuffers가 가리키는 배열의 크기
LPDWORD lpNumberOfBytesRecvd, // 전송된 바이트 수를 저장하기 위한 포인터
DWORD dwFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTING lpCompletionRoutine
);
리턴 : 성공시 0, 실패시 SOCKET_ERROR
lpOverlapped : 중첩된 입출력을 하기 위해 사용.
3. 데이터 송수신 완료 확인
이벤트 커널 오브젝트 기반
CALLBACK 함수 기반
21-3. Event 커널 오브젝트 기반의 Overlapped I/O
이벤트 커널 오브젝트 : 데이터 송수신이 되었는지 확인하는 용도로 사용.
WSACreateEvent
typedef struct _WSAOVERLAPPED{
DWORD Internal;
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
// 위의 4개 변수는 내부적으로 사용.
WSAEVENT hEvent; // 이벤트 핸들의 오브젝트를 저장한다.
}WSAOVERLAPPED, *LPWSAOVERLAPPED;
WSAWaitForMultipleEvents 함수는 이벤트가 시그널 되었는 지 확인한다.
WSAGetOverlappedResult(
SOCKET s,
LPWSAOVERLAPPED lpOverlapped, // WSASend 혹은 WSARecv 호출시 전달한 OVERLAPPED 구조체
LPDWORD lpcbTransfer, // 전송된 바이트 수
BOOL fWait, // TRUE 전달 시 입출력 완료시까지 블로킹
LPDWORD lpdwFlags
);
※ 송수신한 바이트수, 에러가 발생하였는가? 의 결과를 알려준다.
1. 소켓 이벤트와 WSAOVERLAPPED 구조체와 연결하는 방법
event = WSACreateEvent();
memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = event;
2. WSAWaitForMultipleEvents 함수 호출
WSAWaitForMultipleEvents(1, &event, TRUE, WSA_INFINITE, FALSE);
3. WSAGetOverlappedResult 함수 호출
WSAGetOverlappedResult(hSocket, &overlapped, &sendBytes, FALSE, NULL);
21-4. Completion Routines 기반의 Overlapped I/O
콜백 함수 : 특정 상황이 되면 시스템에서 의해 호출되는 함수.
LPWSAOVERLAPPED_COMPLETION_ROUTINE : 다음 콜백함수에 대한 포인터
void CALLBACK CompletionROUTINE(
DWORD dwError, // 오류 정보 전달 됨.
DWORD cbTransferred, // 전송된 바이트 수 전달됨
LPWSAOVERLAPPED lpOverlapped, // WSARecv 함수 호출시 전달한 구조체 변수
DWORD dwFlags
);
콜백함수가 있을지라도 WSAOVERLAPPED 구조체는 전달해 주어야 한다.
그래서 이벤트 커널 오브젝트는 Dummy Object가 된다.
index = WSAWaitForMultipleEvents(1, &event, FALSE, WSA_INFINITE, TRUE);
index가 WAIT_IO_COMPLETION이면 중첩된 입출력이 완료되었다는 뜻.
다른 의미는 오류가 발생함.