삽질의 현장/- 네트워크 프로그래밍

#020_Window_Network_소켓 입출력 모델_WSAAsynvSelect 모델

shovelman 2015. 10. 12. 16:02


안녕하세요 삽잡이입니다.


이번 시간에는 네트워크 입출력 모델 중 WSAAsyncSelect 모델에 대해서 알아보겠습니다.


Async 에는 '비동기적인' 라는 뜻이 있습니다.

그렇다면 이번 시간에 알아볼 WSAAsyncSelect 모델은 비동기적 모델일까요?


다음 시간에 언급하겠지만, 우선 WSAAsyncSelect 모델의 Async는 

여러 작업을 처리할 수 있다는 개념을 나타낸 것입니다.

즉, I/O (입출력) 방식이 비동기 방식이 아니라,

한 클라이언트의 작업이 다 처리되지 못했더라도,

여러 클라이언트들을 같이 작업할 수 있다는 의미에서 Async입니다...

동시 처리가 아닌 여러 작업을 처리한다는 것을 말하는 것이죠.


이해가 안간다면 이전 시간에 배웠던 동기/비동기에 대해서

혹은, 다음에 다시 언급할 때 참고하시길 바랍니다.



WSAAsyncSelect 모델은 MFC의 소켓 과 관련된... 

즉, 클라이언트 TCP 소켓과 관련된 모델이기도 합니다.

윈도우즈에서 사용하는 기본 모델이라는 소리입니다.


이 모델은 쓰레드를 사용하지 않으며, 

소켓 프로그래밍을 프로세저를 사용해서 개발할 수 있다는 장점이 있습니다.


윈도우 프로그램하면 기본적으로 WinMain과 WndProc 프로시저가 있습니다.

프로시저 없이 윈도우 프로그램을 만들 수 없지요...

이와 같이 어차피 있는 프로시저를 가지고 소켓 프로그램을 할 수 있도록 만든 모델입니다.


기본적인 모델을 살펴보도록 하겠습니다.

WndProc 함수의 경우 인자로 핸들과 메시지, wParam, lParam을 받습니다.

즉, WndProc 함수가 호출이 되려면 핸들, 메시지, 파라메터들이 필요하다는 것입니다.


해당 모델은 기존의 WndProc을 통해 소켓 프로그램이 가능하도록 만든 모델입니다.

따라서 WSAAsyncSelect 모델은 소켓에 관련된 정보들도 

위의 인자들을 가지고 호출해보자고하는 모델이라고 할 수 있습니다.


WSAAsyncSelect 모델의 핵심은 select 모델을 보셨으면 유추할 수 있듯이

WSAAsyncSelect() 함수입니다.



해당 함수를 호출해서 소켓 이벤트를 알려줄 윈도우 메시지와 네트워크 이벤트를 등록하게 됩니다.


우선 인자들에 대해서 알아보도록 하겠습니다.

첫번째 인자는 네트워크 이벤트를 처리하고자 하는 소켓을 말합니다.

두번째 인자는 네트워크 이벤트가 발생하면 메시지를 받을 윈도우의 핸들입니다.

세번째 인자는 네트워크 이벤트가 발생하면 윈도우가 받을 메시지를 말합니다.

우리는 이 세번째 인자인 윈도우 메시지를 사용자 정의 메시지로 만들어서 사용합니다.

왜냐하면, 소켓을 위한 윈도우 메시지가 따로 정의되어있지 않기 때문입니다.

마지막 인자는 등록하고자 하는 네트워크 이벤트를 집어넣습니다.



listen_sock에 FD_ACCEPT나 FD_CLOSE 와 같은 네트워크 이벤트가 발생하게 되면 

hWnd(내가 만든 윈도우)에 WM_SOCKET (사용자 정의 메시지)로 알려달라고 등록을 하는 것입니다.


대기 소켓에 의미를 부여한 것입니다.

즉, 이벤트가 발생시 hWnd 윈도우에 WM_SOCKET 메시지를 발생시키도록 의미 부여를 했다 이겁니다.



그렇다면 우리가 위에서 등록 한 네트워크 이벤트가 발생하게 된다면,

윈도우 메시지가 발생하니 WndProc 프로시저가 호출 될 것입니다.

그리고 WndProc 프로시저가 받은 메시지에 따라서 적절하게 일 처리를 하도록 우리가 구현하면 됩니다.


대표적인 네트워크 이벤트에는 ACCEPT, CLOSE, READ, WRITE 가 있습니다.

이런 네트워크 이벤트가 발생하게 되면 등록한 소켓이 관심을 갖는 것이구,

Window 메시지를 만들어 해당 이벤트별로 처리를 하면 된다 이겁니다...


네트워크 이벤트 발생시 윈도우 프로시저에 전달되는 파라메터는 어떨까요?

wParam에는 네트워크 이벤트가 발생한 소켓의 번호가,

lParam의 HIWORD에는 오류코드가, LOWORD에는 네트워크 이벤트가 들어가 있습니다.


WSAAsyncSelect 모델에 대한 특징을 살펴보도록 하겠습니다.

우선, WSAAsyncSelect 모델 또한 선 flag 후 행동 방식의 모델입니다.

미리 등록을 해놓고 이벤트 발생시 그에 따른 행동을 하는 방식이기 때문입니다.

또한, 기존 select 모델과 달리 WSAAsyncSelect() 함수를 호출시 자동으로 넌 블록킹 소켓으로 만들어줍니다.

그리고 중요한 것은 이 모델은 네트워크 이벤트에 대한 검사를 OS가 해줍니다.


이전에 Select 모델은 Application에서 이벤트를 검사했었습니다.

하지만, 이 모델의 경우 OS가 검사하기 때문에 성능이 높아집니다.

이왕 비교한거 계속해서 비교를 해보도록 하겠습니다.

이전에 Select 모델과의 공통점은 '선 플래그 후 행동'방식이라는 것입니다.

그런데 Select 모델의 경우 어플리케이션 영역에서 검사를 해주고,

WSAAsyncSelect 모델의 경우 OS 영역에서 검사를 해준다 이겁니다.


Select 모델과의 차이점은 계속되는 호출이 아닌 단 한번의 호출만을 하는 것입니다.

무슨 말이냐면, 같은 윈도우 메시지를 단 한번만 호출한다는 것입니다.

더 이해가 안가시죠... 아하하...


WSAAsyncSelect 모델은 OS가 이벤트를 감지합니다.

단 한번만 감지하고 난 다음에는 또 감지를 안한다는 것입니다.

즉, 나머지 처리는 수동으로 직접 자신이 해줘야한다는 소리죠...


이러한 상황을 정리해보면

서버 입장에서 데이터를 다 받지 않았지만, 또 데이터가 들어오는 경우를 꼽을 수 있겠군요..


예를 들어서 A라는 서버가 데이터를 계속해서 받고 있었다고 해봅시다.

B라는 클라이언트에게 데이터를 받고 있는 도중에 새로운 데이터가 들어온다고 추가적으로 가정을 해보지요...

그런데, A 서버가 처리할 수 있는 상황이 아니라면 무시를 하는 것이지요...


그렇다면 새로 들어온 데이터는 A 서버의 recv 버퍼에 남아있을 것인데

이 recv 버퍼로 부터 들어있는 데이터가 남아있더라도,

새로 데이터가 들어올 때 까지 데이터가 들어왔다는 호출을 안해준다는 것입니다.

이미 한번 해버렸기 때문이지요...

따라서 수동으로 recv 메시지가 발생하도록 구현하는 몫은 우리에게 있다는 것입니다.


정리해봅시다! WSAAsyncSelect() 함수를 사용할 때에는

한번 메시지가 발생시 그 다음에는 발생하지 않으니 수동으로 발생시켜줘야합니다.

클라이언트가 보낸 데이터를 다 받지 못했지만, 또 보내개 된다면 수동으로 처리해줘야한다 이겁니다.


이상 삽잡이였습니다!