2015년 1월 13일 화요일

TCP/IP 소켓 프로그래밍 21강

21강은 한동안 이해가 안가서 멘붕이었다 ㅡㅡ;
하지만 2번 3번 보니 이해가 가더라....포기하지 않는 것이 제일 중요한 것 같다.

21-1  : 비동기 Notification IO 모델의 이해


-동기(Synchronous)와 비동기(Asynchronous)에 대한 이해-


send 함수가 호출되면 데이터의 전송이 완료된 후에야 반환이 이루어졌다.
함수의 반환이 이루어져야 전송의 완료를 확인하는 것이다.
이런식이다 보니 반환을 기둘리는 CPU 입장에서는 쓸데없이 노는 시간(?)이 생긴 것이다.
이것을 극복하고자 나온 것이 비동기 방식이다.
한마디로 CPU가 쉬는 시간을 주지 않겠다는 것이다.(노동착취 ㅡ_ㅡ)

비동기를 대략적으로 설명하자면 이렇다.

1. send를 호출해서 데이터 전송을 시작한다.
2. 전송이 완료가 되던 말던 CPU는 딴 일을 한다.
3. 전송을 "관찰"하는 함수를 호출한다.
4. 전송 완료가 되면 "관찰하던 함수"가 "send 함수"에게 완료되었다고 알려준다.
5. 관찰하던 함수 종료, send 함수 종료

IO의 상태변화를 알리는 것을 약간 고급스럽게(?) Notification 이라고 한다.

21-2 : 비동기 Notification IO 모델의 이해와 구현


소켓을 대상으로 이벤트 발생여부의 관찰을 명령할 때 사용하는 함수다.

#include <winsock2.h>
int WSAEventSelect(SOCKET s, WSAEVENT hEventObject, long lNetworkEvents);
-> 성공시 0 , 실패시 SOCKET_ERROR 반환

-s : 관찰 대상인 소켓의 핸들 전달
-hEventObject : 이벤트 발생유무의 확인을 위한 이벤트 오브젝트 핸들 전달
-lNetworkEvents : 감시하고자 하는 이벤트의 유형 정보 전달

WSAEventSelect 함수는 매개변수 s에 전달된 핸들의 소켓에서,
세 번째 인자에 전달된 이벤트 중 하나가 발생하면,
두 번째 인자에 전달된 핸들의 커널 오브젝트를 signaled 상태로 바꾸는 함수다.

세 번째 인자에 들어가는 이벤트의 종류를 살펴보자.

FD_READ : 수신할 데이터가 존재하는가?
FD_WRITE : 블로킹 없이 데이터 전송이 가능한가?
FD_OOB : Out-of-band 데이터가 수신되었는가?
FD_ACCEPT : 연결요청이 있었는가?
FD_CLOSE : 연결의 종료가 요청되었는가?

참고로 WSAEventSelect 함수 호출을 통해서 전달된 소켓의 정보는 OS에 등록되고,
이렇게 등록된 소켓에 대해서는  WSAEventSelect 함수의 재호출이 불필요하다.

-manual-reset 모드 Event 오브젝트의 또 다른 생성방법-


이전에는 CreateEvent 함수를 이용해서 이벤트 오브젝트를 생성했다.
 CreateEvent는 이벤트 오브젝트를 생성할 때,
auto-reset 모드와 manual-reset 모드를 선택해서 생성할 수 있는 함수였다.
그러나 여기서 필요한 것은 "manual-reset 모드이면서, non-signaled 상태"인
이벤트 오브젝트다. 이 때 필요한 함수를 보자.

#include <winsock2.h>
WSAEVENT WSACreateEvent(void);
-> 성공시 이벤트 오브젝트 핸들, 실패시 WSA_INVALID_EVENT 반환

위의 함수로 생성된 이벤트 오브젝트 "종료"를 위한 함수는 다음과 같다

#include <winsock2.h>
WSAEVENT WSACloseEvent(WSAEVENT hEvent);
-> 성공시 true, 실패시 false 반환

-이벤트 발생유무의 확인-


WSAEventSelect 함수호출 "이후"를 고민해야한다. "이벤트 발생유무의 확인"을 위해서는
이벤트 오브젝트를 확인해야 한다. 이때 사용하는 함수다.

#include <winsock2.h>
DWORD WSAWaitForMultipleEvents (
      DWORD cEvents, const WSAEVENT* lphEvents,
      BOOL fWaitAll, DWORD dwTimeout, BOOL fAlertable);
-> 성공시 이벤트 발생 오브젝트 관련정보, 실패시 WSA_INVALID_EVENT 반환

-cEvents : signaled 상태로의 전이여부를 확인할 Event 오브젝트의 개수 정보 전달
-lphEvents : Event 오브젝트의 핸들을 저장하고 있는 배열의 주소 값 전달
-fWaitAll : true 전달시 모든 이벤트 오브젝트가 signaled 상태일 때 반환, false 전달시 하나만 signaled 상태가 되어도 반환
-dwTimeout : 1/1000 초 단위로 타임아웃 지정, WSA_INFINITE 전달시 signaled 상태가 될 때까지 반환하지 않는다.
-fAlertable : true 전달시 alertable wait 상태로의 진입

-반환값 : 반환된 정수 값에서 상수 값 WSA_WAIT_EVENT_0을 빼면,
              두 번째 매개변수로 전달된 배열을 기준으로,
              signaled 상태가 된 이벤트 오브젝트의 핸들이 저장된 인덱스가 계산된다.
              만약에 둘 이상의 이벤트 오브젝트가 signaled 상태로 전이되었다면,
              그 중 작은 인덱스 값이 계산된다.
              그리고 타임아웃이 발생하면 WAIT_TIMEOUT 이 반환된다.

위 함수는 소켓의 이벤트 발생에 의해서 이벤트 오브젝트가 signaled 상태가 되어야 반환하는 함수이므로 소켓의 이벤트 발생여부를 확인하기에 좋은 함수다.

-이벤트 종류의 구분-


WSAWaitForMultipleEvents 함수를 통해서 signaled 상태로 전이 된 이벤트 오브젝트까지 알아낼 수 있게 되었으니 이 상태가 된 원인을 확인해야 한다.

#include <winsock2.h>
int WSAEnumNetworkEvents (
          SOCKET s, WSAEVENT hEventObject,
             LPWSANETWORKEVENTS lpNetworkEvents);
-> 성공시 0, 실패시 SOCKET_ERROR 반환

- s : 이벤트가 발생한 소켓의 핸들 전달
- hEventObject : 소켓과 연결된 signaled 상태인 이벤트 오브젝트의 핸들 전달
- lpNetworkEvents : 발생한 이벤트의 유형정보와 오류 정보로 채워질
                              WSANETWORKEVENTS 구조체 변수의 주소 전달

위의 함수를 사용한 소스를 봐야 하는데.....
좀 길어서 여기에 기재하기가 힘들다 ㅡㅜ
역시 소스를 다운 받아 해보는 것이 좋겠다.
소스 코드 다운 받기

댓글 없음:

댓글 쓰기