블로그 이미지
래머
오늘도 열심히 개발하는 개발자입니다.

calendar

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Notice

2014. 5. 2. 01:11 C/C++



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
posted by 래머