Asynchronous Notification IO Model.zip
- 동기(Synchronous)
> send()가 호출되는 순간 데이터의 전송이 시작되고
, send() 호출이 완료(반환)되는 순간 데이터 전송이 완료
> recv()가 호출되는 순간 데이터의 수신이 시작되고
, recv() 호출이 완료(반환)되는 순간 데이터 수신이 완료
( recv()같은 경우 데이터 받을 때 까지 무한 대기 상태이다 )
- 비동기(Asynchronous)
> 입출력 함수의 반환시점과 데이터 송수신의 완료시점이 일치하지 않은 경우
- 동기화 입출력 단점
> 입출력이 진행되는 동안 호출된 함수가 반환을 하지 않아서 다른 일을 할 수 없음
> 비동기화가 해결책, 동기 방식의 단점을 극복한 모델
- 비동기 Notification 입출력 모델에 대한 이해
> 입력 버퍼에 데이터가 수신되어서 데이터의 수신이 필요하거나, 출력버퍼가 비어서 데이터 전송이 가능한 상황의 알림
> Notification IO : IO와 관련해서 특정 상황이 발생했음을 알리는 것
대표적으로 select 방식
-> IO가 필요한, 또는 가능한 상황이 되는 시점이(간단히 말해서 IO관련 이벤트의 발생 시점이)
select()가 반환하는 시점과 일치
> 비동기 Notification IO : IO 상태에 관계 없이 반환이 이루어 지므로 IO 상태 변화를 별도로 관찰해야함
cf. select()도 사실 타임아웃 지정 가능
(기본적으로는 동기화된 NotificationIO 모델이지만 비동기와 유사한 형태 가능)
타임 아웃 후에 다시 IO의 상태변화를 확인 하기 위해서는 핸들을 다시 모아서 select()를 호출 해야함
- IO의 상태 변화
소켓 상태 변화 <----> 소켓에 대한 IO의 상태 변화
소켓 이벤트 발생 <----> 소켓에 대한 IO 관련 이벤트 발생
- 비동기 Notification IO 모델
WSAEventSelect()와 WSAAsyncSelect()가 있음
WSAAsyncSelect()는 발생한 이벤트를 수신할 윈도우의 핸들을 지정해야 함(UI와 관련)
- 비동기 Notification IO 함수
int WSAEventSelect(
SOCKET s, // 소켓 핸들
WSAEVENT hEventObject, // 이벤트 발생 유무 확인을 위한 Event오브젝트 핸들
long lNetworkEvents // 감시하고자 하는 이벤트의 유형
); // 성공 : 0, 실패 : SOCKET_ERROR
> Event 오브젝트와 소켓을 연결하는 함수
> 이벤트 유형 (비트 연산자 이용 가능)
FD_READ 수신할 데이터가 존재
FD_WRITE 블로킹 없이 데이터 전송이 가능
FD_OOB Out-of-band 데이터 수신
FD_ACCEPT 연결 요청
FD_CLOSE 연결의 종료 요청
> 단 하나의 소켓을 대상으로만 함수 호출
select()는 반환되고 나면 이벤트의 발생확인을 위해 다시 모든 핸들을 대상으로 재호출
WSAEventSelect는 소켓의 정보가 OS에 등록이 되어 등록된 소켓에 대해서 재호출 불필요
- manual-reset모드 Event 오브젝트의 또 다른 생성
> CreateEvent()는 auto-reset과 manual-reset중 하나 선택하여 생성 가능
> 여기서 필요한것은 manual-reset 모드이면서 non-signaled상태인 Event오브젝트
#define WSAEVENT HANDLE
WSAEVENT WSACreateEvent(void); // 성공 : 오브젝트 핸들, 실패 : WSA_INVALID_EVENT
- Event 오브젝트 종료
BOOL WSACloseEvnet(WSAEVENT hEvent); // 성공 : TRUE, 실패 : FALSE
- Event 발생 유무 확인
DWORD WSAWaitForMultipleEvents(
DWORD cEvents, // signaled로 전이 여부 확인할 Event 오브젝트 개수
const WSAEVENT* lphEvents, // Event 오브젝트의 핸들을 저장한 배열의 주소
BOOL fWaitAll, // TRUE : 모두 signaled 상태시, FALSE : 하나만 signaled 상태시
DWORD dwTimeout, // 1ms 단위로 타임 아웃 지정, WSA_INFINITE : 무한 대기
BOOL fAlertable // TRUE : alertable wait 상태로 진입
); // 반환 값 - WSA_WAIT_EVENT_0 : signaled 상태가 된 Event 핸들이 저장된 인덱스
둘 이상일 경우 그 중 가장 작은 인덱스
WAIT_TIMEOUT : 타임아웃
> 전달할 수 있는 최대 Event 핸들 수가 64개로 제한
-> 그 이상의 핸들을 관찰할 경우 쓰레드의 생성을 통한 확장이나 배열을 구분해서 함수 두번 호출
cf. WSAWaitForMultipleEvents()가 동시에 관찰할 수 있는 최대 Event 오브젝트 수는 WSA_MAXIMUM_WAIT_EVENTS 상수에서 확인 가능, 변경될 가능성 있음
> 함수가 반환하는 정보는 signaled 상태로 전이된 Event 오브젝트의 첫 번째 인덱스 값이므로 전이된 모든 핸들 정보는 알 수 없지만 Event가 manual-reset 모드를 참고하면 확인 가능
ex)
int posInfo = WSAWaitForMultipleEvents(numOfSock, hEvnetArray, FALSE, WSA_INFINITE, FALSE);
int startIndex = posInfo - WSA_WAIT_EVENT_0;
for(int i = startIndex; i < numOfSock; ++i)
{
int signaledEventIndex = WSAWaitForMultipleEvents(1, &hEventArray[i], TRUE, 0, FALSE);
// TimeOut을 0으로 놓고 배열을 하나씩 탐색
// signaledEvnetIndex에 WAIT_TIMEOUT이 아닐 경우 signaled로 전이된 핸들 인덱스 값
}
- Event 종류 구분
int WSAEnumNetworksEvents(
SOCKET s,
WSAEVENT hEventObject,
LPWSANETWORKEVENTS lpNetworkEvents
); // 성공 : 0, 실패 : SOCKET_ERROR
> manual-reset모드의 Event를 non-signaled 상태로 되돌림
(발생한 이벤트 유형을 확인한 다음 ResetEvent()를 호출할 필요 없음)
typedef struct _WSANETWORKEVENTS
{
long lNetworkEvents;
int iErrorCode[FD_MAX_EVENTS];
} WSANETWORKEVENTS, *LPWSANETWORKEVENTS;
> WSANETWORKEVENTS 구조체에 이벤트 정보가 담김
> 수신할 데이터가 존재하면 FD_READ, 연결요청이 있는 경우 FD_ACCEPT
ex)
WSANETWORKEVENTS netEvents;
WSAEnumNetworkEvents(hSocks, hEvents, &netEvents);
if(netEvents.lNetworkEvnets & FD_ACCEPT)
{ /* FD_ACCEPT 이벤트 발생 */ }
if(netEvents.lNetworkEvnets & FD_READ)
{ /* FD_READ 이벤트 발생 */ }
if(netEvents.lNetworkEvnets & FD_CLOSE)
{ /* FD_CLOSE 이벤트 발생 */ }
> 오류발생 정보는 iErrorCode에 담김
* FD_XXX 관련 오류 : iErrorCode[FD_XXX _BIT]에 0 이외에 값
-> FD_READ 관련 오류 : iErrorCode[FD_READ_BIT]에 0 이외에 값
-> FD_WRITE 관련 오류 : iErrorCode[FD_WRITE_BIT]에 0 이외에 값
ex)
WSANETWORKEVENTS netEvents;
WSAEnumNetworkEvents(hSocks, hEvents, &netEvents);
if(netEvents.iErrorCode[FD_READ_BIT] != 0)
{ /* FD_READ 이벤트 관련 오류 */ }
'programing > Networks' 카테고리의 다른 글
IOCP(Input Output Completion Port) (1) | 2015.06.02 |
---|---|
Overlapped IO 모델 (0) | 2015.06.01 |
표준 입출력 함수, 입출력 스트림, select()의 문제, 쓰레드 (0) | 2015.05.21 |
멀티 캐스트& 브로드 캐스트 (0) | 2015.05.18 |
입출력 함수 (0) | 2015.05.18 |