728x90

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;
}

 

728x90

+ Recent posts