타임아웃을 위한 비동기 소켓 접속시 select 에는 보통 아래와 같은 패턴으로 오류점검을 하게 된다. 이때 select 함수에 사용되는 3개의 fd_set 이 의미하는 바는 아래와 같다.
...
iRet = WSAStartup( ... );
...
skConnect = socket( ... );
...
iRet = ioctlsocket( skConnect, FIONBIO, &lNonBlock );
...
if ( SOCKET_ERROR == connect( ... )
{
	FD_ZERO(&wset);
	FD_SET(skConnect, &wset);

	FD_ZERO(&eset);
	FD_SET(skConnect, &eset);

	iRet = select((int)(SOCKET)skConnect+1, NULL, &wset, &eset, &timeout);

	...

	if( !FD_ISSET(skConnect, &wset) || FD_ISSET(skConnect, &eset) )
	{
		///
	}
	...
}
  • readfds
    • 해당 소켓에 대해 수신할 데이터가 있으면 세팅된다.
    • 해당 소켓이 끊어졌으면 세팅된다.
    • 해당 소켓이 listen 후에 새로운 연결이 대기중이어서 accept가 성공할 가능성이 있으면 세팅된다.
  • writefds
    • 해당 소켓을 통해 데이터가 송신되었으면 세팅된다.
    • 해당 소켓이 넌블럭모드에서 연결을 시도했다면, 연결이 성공하였을 경우 세팅된다.
  • exceptfds
    • 해당 소켓이 넌블럭모드에서 연결을 시도했다면, 연결이 실패하였을 경우 세팅된다.
    • 해당 소켓에 대해 수신할 OOB 데이터가 있으면 세팅된다.
여기서 OOB 데이터는 중요한 데이터라는 의미에서 대역 외 데이터(Out of Band Data)라는 뜻인데, 이것은 TCP URG 1bit와 TCP 세크먼트 헤더를 이용해서 OOB인 것으로 처리되는데 Telnet과 Rlogin 등에서는 사용되지만 일반적인 경우 사용하지 않으니 염두에 둘 필요는 없다. 중요한 것은, select 에는 최소한 1개 이상의 fd_set이 있어야 한다. 위의 예제의 경우, 비동기로 소켓을 접속 시도한 후 writefds 가 세팅되어 있지 않거나 (연결이 성공하지 못했거나) exceptfds 가 세팅되어 있으면 ( 연결이 실패했거나 ) 예외 처리를 하도록 유도한 코드의 예이다. 마지막으로 WSAGetLastError()로 제대로 에러값을 가져오지 못하는 경우가 생기는데 이때에는 아래의 코드를 사용하면 에러코드를 가져올 수 있다.
getsockopt( pCtx->hSocket, SOL_SOCKET, SO_ERROR, (char*)&dwOptError, &dwOptErrorLen );
끝.
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기