WSAEventSelect
- WSAEventSelect : 성공 시 0, 실패 시 SOCKET_ERROR 반환
int WSAEventSelect(SOCKET s,WSAEVENT hEventObject, long lNetworkEvents);
-> s : 관찰대상의 소켓 핸들
-> hEventObject : 등록한 이벤트가 발생했음을 확인하기 위한 커널 오브젝트의 핸들
-> lNetworkEvent : 감시하고자 하는 이벤트의 유형 정보
-> lNetWorkEvent로 등록한 이벤트가 발생하면 hEventObject가 signaled 상태로 바뀜
Event 커널 오브젝트
- WASCreateEvent : Event 커널 오브젝트 생성
-> 생성된 커널 오브젝트는 manual-reset 모드
- WASCloseEvent : Event 커널 오브젝트 소멸
WSAEVENT WSACreateEvent(void);
WINBOOL WSACloseEvent(WSAEVENT hEvent);
- WSAWaitForMultipleEvents : 이벤트 오브젝트를 확인해서 이벤트가 발생했는지를 확인
DWORD WSAWaitForMultipleEvents(DWORD cEvents,const WSAEVENT *lphEvents,
WINBOOL fWaitAll,DWORD dwTimeout,WINBOOL fAlertable);
-> 성공 시 이벤트 발생 오브젝트 관련 정보, 실패 시 WSA_INVALID_EVENT(NULL) 반환
-> 이벤트 관련 정보에서 WSA_WAIT_EVENT_0를 빼면 발생한 이벤트 오브젝트 배열의 인덱스 전달
-> 타임아웃 시 WAIT_TIMEOUT 반환
-> cEvent : 이벤트 오브젝트의 개수
-> lphEvents : Event 오브젝트 핸들을 저장하고 있는 배열의 주소 값
-> fWaitAll : TRUE를 전달하면 모든 오브젝트가 signaled 상태일 때 반환, FALSE를 전달하면 하나라도 signaled 상태가 되면 반환
-> dwTimeout : 타임아웃. WSA_INFINITE (0xffffffff) 시 무한 대기
-> fAlertable : TRUE 전달 시 alertable wait 상태로 진입
- WSAEnumNetworkEvents : 이벤트 종류의 구분
int WSAEnumNetworkEvents(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents);
typedef struct _WSANETWORKEVENTS {
__LONG32 lNetworkEvents; // 발생한 이벤트 저장
int iErrorCode[FD_MAX_EVENTS]; // 해당 액션에 대한 오류 정보 없으면 0
} WSANETWORKEVENTS,*LPWSANETWORKEVENTS;
-> s : 소켓 핸들
-> hEventObject : 소켓과 연결된 이벤트 오브젝트
-> lpNetworkEvent : 발생한 이벤트의 유형 정보 및 오류 정보
int main(int argc, char *argv[])
{
WSADATA wsaData;
SOCKET hServSock, hClntSock;
SOCKADDR_IN servAdr, clntAdr;
SOCKET hSockArr[WSA_MAXIMUM_WAIT_EVENTS]; // 소켓 저장용 배열
WSAEVENT hEventArr[WSA_MAXIMUM_WAIT_EVENTS]; // 이벤트 오브젝트 저장용 배열
WSAEVENT newEvent; // 이벤트 오브젝트
WSANETWORKEVENTS netEvents; // 발생한 이벤트 정보 저장용
int numOfClntSock=0;
int strLen, i;
int posInfo, startIdx;
int clntAdrLen;
char msg[BUF_SIZE];
if(argc!=2) {
printf("Usage: %s <port>\n", argv[0]);
exit(1);
}
if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
ErrorHandling("WSAStartup() error!");
hServSock=socket(PF_INET, SOCK_STREAM, 0);
memset(&servAdr, 0, sizeof(servAdr));
servAdr.sin_family=AF_INET;
servAdr.sin_addr.s_addr=htonl(INADDR_ANY);
servAdr.sin_port=htons(atoi(argv[1]));
if(bind(hServSock, (SOCKADDR*) &servAdr, sizeof(servAdr))==SOCKET_ERROR)
printf("bind() error");
if(listen(hServSock, 5)==SOCKET_ERROR)
printf("listen() error");
newEvent=WSACreateEvent(); // event 오브젝트 생성
if(WSAEventSelect(hServSock, newEvent, FD_ACCEPT)==SOCKET_ERROR)
// 서버 소켓 이벤트 발생 감시 등록
printf("WSAEventSelect() error");
hSockArr[numOfClntSock]=hServSock; // 소켓 배열에 저장
hEventArr[numOfClntSock]=newEvent; // event 오브젝트 배열 저장
numOfClntSock++;
while(1)
{
posInfo=WSAWaitForMultipleEvents(
numOfClntSock, hEventArr, FALSE, WSA_INFINITE, FALSE);
startIdx=posInfo-WSA_WAIT_EVENT_0; // 반환 값을 빼면 이벤트가 발생한 오브젝트의 인덱스
for(i=startIdx; i<numOfClntSock; i++)
{
int sigEventIdx=
WSAWaitForMultipleEvents(1, &hEventArr[i], TRUE, 0, FALSE);
// 다음으로 하나씩 이벤트가 발생되었는 지 비교
// 이벤트 오브젝트가 manual-reset이기 때문에 아직 signaled 상태
if((sigEventIdx==WSA_WAIT_FAILED || sigEventIdx==WSA_WAIT_TIMEOUT))
{
continue;
}
else
{
sigEventIdx=i;
WSAEnumNetworkEvents(
hSockArr[sigEventIdx], hEventArr[sigEventIdx], &netEvents);
// 해당 이벤트 오브젝트, 소켓에 발생한 이벤트 확인
if(netEvents.lNetworkEvents & FD_ACCEPT)
{
if(netEvents.iErrorCode[FD_ACCEPT_BIT]!=0)
{
puts("Accept Error");
break;
} // 오류 발생 체크
clntAdrLen=sizeof(clntAdr);
hClntSock=accept(
hSockArr[sigEventIdx], (SOCKADDR*)&clntAdr, &clntAdrLen);
newEvent=WSACreateEvent();
WSAEventSelect(hClntSock, newEvent, FD_READ|FD_CLOSE);
// 새로 연결된 클라이언트 소켓도 등록
hEventArr[numOfClntSock]=newEvent;
hSockArr[numOfClntSock]=hClntSock;
numOfClntSock++;
puts("connected new client...");
}
if(netEvents.lNetworkEvents & FD_READ)
{
if(netEvents.iErrorCode[FD_READ_BIT]!=0)
{
puts("Read Error");
break;
} // 오류 발생 체크
strLen=recv(hSockArr[sigEventIdx], msg, sizeof(msg), 0);
send(hSockArr[sigEventIdx], msg, strLen, 0);
}
if(netEvents.lNetworkEvents & FD_CLOSE)
{
if(netEvents.iErrorCode[FD_CLOSE_BIT]!=0)
{
puts("Close Error");
break;
} // 오류 발생 체크
WSACloseEvent(hEventArr[sigEventIdx]);
closesocket(hSockArr[sigEventIdx]);
numOfClntSock--;
CompressSockets(hSockArr, sigEventIdx, numOfClntSock);
CompressEvents(hEventArr, sigEventIdx, numOfClntSock);
} // 각 이벤트에 대한 처리
}
}
}
WSACleanup();
return 0;
}
'Programming > Network' 카테고리의 다른 글
열혈 TCP/IP 22-2. Overlapped IO에서의 입출력 완료의 확인 (0) | 2021.04.25 |
---|---|
열혈 TCP/IP 22-1. Overlapped IO 모델의 이해 (0) | 2021.04.25 |
열혈 TCP/IP 21-1. 비동기 Notification IO 모델의 이해 (0) | 2021.04.13 |
열혈 TCP/IP 20-2. 커널모드 동기화 기법 (0) | 2021.04.11 |
열혈 TCP/IP 20-1. 동기화 기법의 분류와 CRITICAL_SECTION 동기화 (0) | 2021.04.11 |