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

#021_Window_Network_소켓 입출력 모델_WSAEventSelect 모델

shovelman 2015. 10. 12. 19:50


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


이번 시간에는 WSAEventSelect 모델에 대해서 알아보려고합니다.


WSAEventSelect모델은 지난 시간에 배운 WSAAsyncSelect 모델과 비슷합니다.

하지만, WSAAsyncSelect 모델은 윈도우가 없으면 안됩니다.

어떤 윈도우의 메시지를 발생시켜 프로시저를 호출 할 것이냐 하는 것이 

WSAAsyncSelect 모델이기 때문입니다.


네트워크 처리 속도가 좀 걸리는 것(?)들은 윈도우 메시지 메시지 처리와 함께 해줘야 하기 때문에

쓰레드 하나로 모든 처리를 하기 벅찰 수 있습니다.

그러니 쓰레드 하나로 벅차다 해서 윈도우 없이도 동작할 수 있는 동기 입출력 방식을 만들어 냈습니다.

그게 바로 WSAEventSelect 모델이구요...


그렇다면 WSAEventSelect 모델은 뭐가 다를까요?

바로 '커널 오브젝트'를 사용한다는 것입니다.


네트워크 이벤트는 모두 'FD_'로 시작합니다.

그런데 이전 WSAAsyncSelect 모델은 메세지로 만들어 달라고 요청을 했는데

이제는 'Kernel Object Event'로 만들어달라고 하는 것입니다.


커널 오브젝트와 통신 소켓을 연결 시킨다는 것입니다.

그리고 WaitForMultipleEvents() 함수를 사용하게 됩니다.


뭔말이냐,

소켓과 이벤트 객체(커널 오브젝트)를 생성하여 짝 지어두게 된다면

네트워크 이벤트가 발생한 사실을 Application에서 알 수 있게 되는 것입니다.

OS만 알고 있던 네트워크 이벤트를 말입니다...


WaitForMultipleEvents() 함수를 사용하는 이유는,

신호 상태가 된 커널 오브젝트에 네트워크 이벤트가 발생했다는 사실을 알 수 있게 되기 때문입니다.


윈도우가 사용하지 않습니다.

즉, 윈도우 없이도 어플리케이션에 네트워크 상황을 보고 받을 수 있다는 것입니다.

WSAEventSelect 모델 또한 선 플래그 후 행동 모델입니다.


간략하게 사용하는 코드를 확인해보도록 하겠습니다.


WSAEventSelect 모델의 핵심은 역시 WSAEventSelect() 함수입니다.



예시를 살펴보도록 하겠습니다.



'이 client_sock(소켓)에 네트워크 이벤트(FD_ACCEPT, FD_CLOSE)가 발생하게 된다면

커널 오브젝트 이벤트(EventArray[nTotalSockets-1])를 신호 상태로 만들라.' 는 뜻입니다.


즉, 소켓과 커널 오브젝트를 짝지어주고, 

처리할 네트워크 이벤트를 등록해주는 기능을 담당하고 있습니다.

즉, 관심있는 네트워크 이벤트를 등록하는 것입니다.


이벤트를 감시하기 위해서는 WSAWaitForMultipleEvents() 함수를 사용합니다.

WaitForMultipleObject 함수와 똑같은 함수입니다...

 


첫번째 인자에는, 커널 오브젝트들의 개수

두번째 인자에는, 커널 오브젝트들이 담겨있는 핸들 테이블의 주소

세번째 인자에는, 모든 커널 오브젝트들이 신호상태가 될지 아니면 하나라도 신호상태가 되면 알릴지

네번째 인자에는, 대기시간

마지막 인자에는 나중에 언급하도록 하겠습니다. 우선은 FALSE로 지정하도록 하겠습니다.


해당 함수가 return 되게 되면 어느 커널 오브젝트가 신호상태가 됬는지 반환하게 됩니다.


 

즉, 어떤 함수가 신호 상태가 됬는지를 return 하게 되는데 이 값은 index 번호를 받습니다.


사실, 우리는 네트워크 어떤 소켓이 어떤 이벤트가 발생했냐에 관심을 가지고 있습니다.

진짜로 커널 오브젝트 이벤트가 신호 상태가 되는 것에 관심이 있다는 것이 아닙니다.

그래서 확인을 위해 만든 것이지 않습니까...

즉, 우리는 통신 소켓, 대기 소켓등에 어떤 네트워크 이벤트가 발생했는지에 대해 관심이 있다는 것입니다.


우리는 WSAWaitForMultipleEvents 함수를 통해 인덱스 번호가 나오지요...

알고 있는 정보가 인덱스 번호 밖에 없습니다.

따라서 어던 커널 오브젝트들이 신호 상태가 된것인지 밖에 모른다 이겁니다.


그래서 이때에는 테이블 매핑 방식을 사용합니다.

커널 오브젝트들을 배열에 넣고,

어플리케이션 쪽에서도 소켓 테이블을 만들어서 

똑같이 커널 오브젝트가 담긴 순서대로 담는다 이겁니다...

그렇게 되면 신호 상태로 변경시 테이블의 똑같은 순서에 신호 상태가 된것을 확인할 수 있습니다.



따라서 두개의 배열이 필요하게 되는 것입니다.

결과적으로 등록, 제거 모두 항상 쌍으로 수행시키도록 말입니다.


 

WSACreateEvent() 함수는 수동 이벤트를 만들어주는 함수입니다.

 


따라서 소켓에 대한 정보를 저장함과 같이 같은 순서에

WSACreateEvent() 함수를 통해 만든 이벤트를 저장시키는 것입니다.


예를 들어서... 소켓 정보를 추가한다고 했을 때

socket의 정보와, 커널 오브젝트를 똑같은 인덱스값으로 각각의 배열에 저장시킨다 이겁니다.


자... 이처럼



네트워크 이벤트가 일어날 때 까지 대기를 하고 있다가 return을 통해 index번호가 반환되면,

우리는 이전에 수동 이벤트를 만들었기 때문에,

신호 상태로 그대로 남아있게됩니다.


그렇다면, 이제 이 네트워크 모델에서 가장 중요한 함수중 하나인 

WSAEnumNetworkEvents() 함수를 주목해야합니다.



해당 함수는 소켓과 관련해서 발생한 구체적인 네트워크 이벤트를 알려줍니다. 


이 함수의 핵심은 두가지입니다.

우선, 우리가 알고 있는 index 번호의 이벤트가 신호 상태가 됬다는 것만을 알지

어떠한 이벤트가 발생된지는 모릅니다. 이를 확인할 수 있습니다.

그리고 수동 이벤트를 자동으로 비신호 상태로 만들어줍니다.


정리하자면 두가지 작업을 하는데,

소켓의 이벤트를 세번째 인자를 통해 Out 파라메터로 알려주고,

커널 오브젝트의 핸들의 상태를 바꿔주는 작업을 한다는 것입니다.


설명이 많이 미흡한거 같습니다...

우선은... 여기까지 하도록 하겠습니다.


이상 삽잡이였습니다!



참고 : TCP/IP 윈도우 소켓 프로그래밍