동기와 비동기에 대한 이해
위 : 동기
아래 : 비동기
*동기화된 입출력의 단점과 비동기의 해결책
동기화된 입출력의 단점
입출력이 진행되는 동안 호출된 함수가 반환을 하지 않으니, 다른 일을 할 수가 없다
비동기의 해결책
데이터의 송수신 완료에 상관없이, 호출된 함수가 반환을 하기 때문에 다른 일을 진행 할
수 있음
*Notification(알림) IO(입출력)
입력버퍼에 데이터가 수신되어서 데이터의 수신이 필요하거나, 출력버퍼가 비어서
데이터의 전송이 가능한 상황의 알림
*동기화된 Notification IO모델
가장 대표적인 동기화된 Notification IO모델은 select방식
IO가 필요한 또는 가능한 상황이 되는 시점이(간단히 말해서 IO관련 이벤트의 발생
시점이) select함수가 반환하는 시점과 일치한다
*비동기 Notification IO모델
WSAEventSelect함수가 해당됨
IO의 관찰을 명령하기 위한 함수호출과 실제로 상태의 변화를 확인하는 함수호출
*비동기 Notification IO모델의 구현방법
1. WSAEventSelect 함수
2. WSAAsyncSelect 함수
비동기 Notification IO모델의 구현 순서
1. WSACreateEvent() : manual-reset모드 Event 오브젝트 생성, 배열에 내용저장
2. WSAEventSelect() :
소켓과 Event 오브젝트를 연결하여 소켓의 이벤트 발생시 Event 오브젝트가 signaled상태로 바뀜, os에 등록
3. WSAWaitForMultipleEvents() : WSAEVENT배열에서 signaled 상태로 전이된 Event 오브젝트를 찾음
4. WSAEnumNetworkEvents() : 소켓과 소켓에 연결된 Event 오브젝트의 핸들을 통해 발생한 이벤트의 유형정보, 오류정보를 알아냄
manual-reset모드 Event 오브젝트의 생성함수
#include <winsock2.>
WSAEVENT WSACreateEvent(void);
성공 시 Event 오브젝트 핸들, 실패 시 WSA_INVALID_EVENT 반환
#define WSAEVENT HANDLE 라고 정의되어 있음
manual-reset모드 Event 오브젝트의 삭제함수
#include <winsock2.h>
BOOL WSACloseEvent(WSAEVENT hEvent);
성공 시 TRUE, 실패 시 FALSE반환
임의의 소켓을 대상으로 이벤트 발생여부의 관찰을 명령하는 함수
매개변수 s에 전달된 핸들의 소켓에서 lNetworkEvents에 전달된 이벤트 중 하나가 발생하면, hEventObject에 전달된 핸들의 커널 오브젝트를 signaled 상태로 바꾸는 함수
#include <winsock2.h>
int WSAEventSelect(SOCKET s, WSAEVENT hEvvnetObject, long lNetworkEvents);
성공시 0, 실패시 SOCKET_ERROR 반환
s : 관찰대상인 소켓의 핸들 전달
hEventObject : 이벤트 발생유무의 확인을 위한 Event 오브젝트의 핸들 전달
lNetworkEvents : 감시하고자 하는 이벤트의 유형 정보전달
3번째 인자로 전달될 수 있는 이벤트의 종류
1. FD_READ 수신할 데이터가 존재하는가?
2. FD_WRITE 블로킹 없이 데이터 전송이 가능한가?
3. FD_OOB out-of-band 데이터가 수신되었는가?
4. FD_ACCEPT 연결요청이 있었는가?
5. FD_CLOSE 연결의 종료가 요청되었는가?
이벤트 발생유무의 확인하는 함수(= WaitForMultipleObjects함수)
#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 전달 시 모든 Event 오브젝트가 signaled 상태일 때 반환, FALSE 전달 시 하나만 signaled 상태가 되어도 반환
dwTmeout : 1/1000초 단위로 타임아웃 지정, WSA_INFINITE 전달 시 signaled 상태가 될 때까지 반환하지 않는다
fAlertable : TRUE 전달 시, alertable wait 상태로의 진입
반환 값 : 반환된 정수 값에서 상수 값 WSA_WAIT_EVENT_0을 빼면, 두 번째 매개변수로 전달된 배열을
기준으로, signaled상태가 된 Event 오브젝트의 핸들이 저장된 인덱스가 계산된다.
만약에 둘 이상의 Event 오브젝트가 signaled상태로 전이 되었다면, 그 중 작은 인덱스 값이
계산된다.
그리고 타임아웃이 발생하면 WAIT_TIMEOUT이 반환된다.
해당 오브젝트가 signaled 상태가 된 원인을 확인하는 함수
#include <winsock2.h>
int WSAEnumNetworkEvents(
SOCKET s, WSAEVENT hEvnetObject, LPWSANETWORKEVENTS lpNetworkEvents);
성공 시 0, 실패 시 SOCKET_ERROR 반환
s : 이벤트가 발생한 소켓의 핸들 전달
hEventObject : 소켓과 연결된(WSAEventSelect 함수 호출에 의해), signaled 상태인 Event 오브젝트의
핸들 전달
lpNetworkEvents : 발생한 이벤트의 유형정보와 오류정보로 채워질 WSANETWORKEVENTS 구조체 변수의
주소 값 전달
typedef struct _WSANETWORKEVENTS
{
long lNetworkEvents;
int iErrorCode[FD_MAX_EVENTS];
} WSANETWORKEVENTS, *LPWSANETWORKEVENTS;
발생한 이벤트의 종류를 확인하는 방법
WSANETWORKEVENTS netEvents;
WSAEnumNetworkEvents(hSock, hEvent, &netEvents);
if(netEvents.lNetworkEvents & FD_ACCEPT)
{
// FD_ACCEPT 이벤트 발생에 대한 처리
}
오류발생에 대한 정보를 확인하는 방법
WSANETWORKEVENTS netEvents;
WSAEnumNetworkEvents(hSock, hEvent, &netEvents);
if(netEvents.iErrorCod[FD_READ_BIT] != 0)
{
// FD_READ 이벤트 관련 오류발생
}