WSAEventSelect 모델
WSAEventSelect 모델은 윈도우 메시지 대신에 이벤트 객체를 이용한다는 점을 제외하면 WSAAsyncSelect 모델과 여러 가지로 비슷하다. 물론 표 4에 나와있는 네트워크 이벤트도 WSAAsyncSelect 모델과 공유해 쓸 수 있다. WSAEventSelect 모델을 쓰려면 먼저 다음과 같이 WSACreateEvent 함수를 이용해 이벤트 객체를 만들어야 한다.
WSAEVENT WSACreateEvent(void);
WSACreateEvent 함수를 통해 이벤트 객체를 만들었으면 이 이벤트 핸들을 소켓에 연결해야 한다(이때 원하는 이벤트를 지정해야 한다). 이 작업은 WSAEventSelect 함수를 통해 이루어지며, 다음은 이 함수의 원형이다.
int WSAEventSelect (
SOCKET s,
WSAEVENT hEventObject,
long lNetworkEvents
);
첫 번째 인자 s는 소켓을 나타내며, 두 번째 인자 hEventObject는 WSA CreateEvent를 통해 얻은 이벤트 객체를, 마지막 인자 lNetworkEvents는 네트워크 이벤트 타입이다.
WSACreateEvent는 논시그널드(nonsignaled) 상태의 매뉴얼 리셋(manual reset) 이벤트를 생성한다. 그러므로 이벤트가 시그널 상태로 되어 적절한 처리를 해준 후 다시 논시그널드 상태로 되돌리려면 다음의 WSA ResetEvent 함수를 호출해야 한다.
BOOL WSAResetEvent(
WSAEVENT hEvent
);
응용 프로그램에서 이벤트 객체의 사용을 마치고 제거하려면 다음 WSACloseEvent 함수를 이용해 이벤트 객체를 해제해 주어야 한다.
BOOL WSACloseEvent(
WSAEVENT hEvent
);
WSAAsyncSelect의 윈도우 프로시저에서 메시지를 처리하는 부분은 WSAWaitForMultipleEvents 함수를 통해 이루어지며 이 함수의 원형은 다음과 같다.
DWORD WSAWaitForMultipleEvents(
DWORD cEvents,
const WSAEVENT FAR *lphEvents,
BOOL fWaitAll,
DWORD dwTimeOUT,
BOOL fAlertable
);
WSAWaitForMultipleEvents 함수는 WIN32의 WaitForMultipleEvents 함수와 비슷한 기능을 하며 대부분의 인자 배열도 비슷하다. 단지 이 함수가 동시에 처리할 수 있는 이벤트 객체의 수는 64개로 고정되어 있다. 다시 말해 이 모델은 한 스레드에서 64개의 소켓까지만 지원할 수 있다.
WSAWaitForMultipleEvents 함수의 반환 값을 통해 어느 이벤트 객체가 시그널드 상태로 됐는지 알아낼 수 있고 다음의 WSAEnumNetworkEvents 함수를 통해 어떤 네트워크 이벤트가 발생했는지 조사할 수 있다.
int WSAEnumNetworkEvents (
SOCKET s,
WSAEVENT hEventObject,
LPWSANETWORKEVENTS lpNetworkEvents
);
마지막 인자는 WSANETWORKEVENTS 구조체에 대한 포인터이며, 발생한 네트워크 이벤트와 에러 코드를 담고 있다. 그 구조는 다음과 같다.
typedef struct _WSANETWORKEVENTS {
long lNetworkEvents;
int iErrorCode[FD_MAX_EVENTS];
} WSANETWORKEVENTS, FAR * LPWSANETWORKEVENTS;
구조체에서 네트워크 이벤트를 조사하면서 그 이벤트에 대하여 에러가 발생했는지 같이 검사해야 한다. 다음의 예제와 같이 FD_READ 이벤트가 발생한 경우 이에 해당하는 에러코드의 배열(FD_READ_BIT)도 검사해 동작이 성공했는지 알아봐야 한다.
if (NetworkEvents.lNetworkEvents & FD_READ) {
if (NetworkEvents.iErrorCode[FD_READ_BIT] != 0) {
printf(“FD_ERROR failed with error %d \n”,
NetworkEvents.iErrorCode[FD_READ_BIT]);
}
}
리스트 3은 WSAEventSelect 모델을 사용하는 프로그램의 부분적인 코드이다.
리스트 2 : WSAAsyncSelect 모델 예제
main()
{
// 생략
Listen = socket ()
WSAAsyncSelect(Listen, Window, WM_SOCKET, FD_ACCEPT|FD_CLOSE);
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT);
bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr));
listen(Listen, 5);
while(Ret = GetMessage(&msg, NULL, 0, 0))
{
if (Ret == -1)
{
printf(“GetMessage() failed with error %d\n”, GetLastError());
return;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
} // main 함수
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
SOCKET Accept;
LPSOCKET_INFORMATION SocketInfo;
DWORD RecvBytes, SendBytes;
DWORD Flags;
if (uMsg == WM_SOCKET)
{
if (WSAGETSELECTERROR(lParam))
{
printf(“Socket failed with error %d\n”, WSAGETSELECTERROR(lParam));
FreeSocketInformation(wParam);
}
else
{
switch(WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT:
Accept = accept(wParam, NULL, NULL));
WSAAsyncSelect(Accept, hwnd, WM_SOCKET,
FD_READ|FD_WRITE|FD_CLOSE);
break;
case FD_READ:
// 데이터 읽기 작업
break;
case FD_WRITE:
// 데이터 쓰기 작업
break;
case FD_CLOSE:
closesocket(wParam);
break;
}
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
'C/C++' 카테고리의 다른 글
[본문스크랩] [MSSQL] 함수 (0) | 2014.05.02 |
---|---|
[본문스크랩] [펌]초급 : 간단하게 OLEDB 사용하기 (0) | 2014.05.02 |
WSAEventSelect (0) | 2014.05.02 |
WSASend (0) | 2014.05.02 |
소켓 입출력 모델 - Overlapped 모델 (0) | 2014.05.02 |