오전 11:26 2002-01-11
조경민 bro(bro@shinbiro.com) 윈속 소켓 정리
=====================================================================

소켓이 생성되면 기본적으로 블러킹 소켓(동기소켓,blocking socket)이 된다.
윈속 블러켕 소켓에서는 해당 작업이 바로 처리되지 못한다면 수행이 완료될때
까지 멈추게 된다.
소켓 리소스를 쓰지 못하는 상황에서는 수행은 실패(SOCKET_ERROR)로
리턴되며 WSAGetLastError() 호출시 WSAEWOULDBLOCK에러로 발생되게 된다.
이런 경우엔, 다시 쓸 수 있게 되는 시점에서 다시 해당 수행을 시도해야한다.

넌블러킹소켓(비동기소켓,non-blocking socket)으로 만들려면
비동기 소켓으로 만드는 법
1. ioctlsocket를 FIONBIO 명령으로 주거나
2. WSAEventSelect
3. WSAAyncSelect
를 이용한다.

Overlapped Socket은 프로그래밍 모델상 Blocking Socket과 Non-Blocking socket
과는 관계가 없다. 이론적으로는 블러킹소켓에서든 넌블러킹소켓에서든 오버랩드
기능은 제공되어야 하나 현재, 윈속은 넌블러킹 모드의 소켓에 대해서만 오버랩드
를 지원하게 된다.

WSAAsyncSelect는 소켓 이벤트 통보를 윈도우 메시지에 연결시키게 되어 싱글 스레드
GUI 애플리케이션을 위한 최고의 모델이 될 수 있다.

WSAEventSelect는 WSAWaitForMultipleEvents를 이용해 네트워크 이벤트가 도착할때까지
기다리다가 이벤트가 도착하면 WSAEnumNetworkEvents를 이용하여 소켓 이벤트 상태를
얻어와 소켓 이벤트 통보를 할 수 있도록 한다.


오버랩드 모드로 소켓을 생설하려면
( 오버랩드를 쓰지 않더라도 WSASocket을 쓰면 WSA_FLAG_OVERLAPPED를 함께
주는것이 Win95/NT 호환문제로 추천한다
INFO: WSA_FLAG_OVERLAPPED Is Needed for Non-Blocking Sockets MSDN 참조)

WSASocket함수 호출시 WSA_FLAG_OVERLAPPED를 플래그로
함께 주면 오버랩드 소켓으로 생성된다. 이때 어떤 수행이 바로 완료되지 못하
게 되면 바로 해당 수행에 대해 실패(SOCKET_ERROR)가 리턴되며 WSAGetLastError()
나 GetLastError() 로 실패 이유를 체크하면 WSA_IO_PENDING나 ERROR_IO_PENDING가
리턴딘다. 이렇게 리턴되는 경우엔 언젠가 해당 작업이 완료가 될것이므로 안료루틴을
만들어 타게 하거나 차후에 GetOverlappedResult 함수로 완료가 되었는지 알아내거나
완료될때까지 기다릴 수 있다.
오버랩드 속성으로 소켓을 생성했다고 오버랩드 수행이 일어나지는 않는다.
예로 WSARecv/WSASend시 Overlapped 구조체나 Completion 함수를 NULL로 주게되면
오버랩드 동작이 아닌 recv와 같은 동작을 하게된다.

Winsock 1 에서는 오버랩드 소켓을 생성(socket)후 ReadFile/WriteFile 등으로
오버랩드 I/O 작업을 하였다.
Winsock 2에서는 WSASocket를 WSA_FLAG_OVERLAPPED로 오버랩드 솤켓을 생성 후
ReadFile/WriteFile 또는 WSASend, WSASendTo, WSARecv, WSARecvFrom 함수를 이용해
오버랩드 I/O 작업을 할 수 있다.

만일 setsockopt를 SO_RCVBUF와 SO_SNDBUF 옵션으로 TCP스택의 받는 버퍼와 보내는
버퍼의 크기를 0 으로 주게 되면, I/O 작업 호출시 바로 직접 사용자의 버퍼를
이용하여 I/O 작업을 하게끔 할 수 있다. 이는 넌블러킹 소켓에서 Overlapped 소켓
에서 매번 I/O 호출에 대해 TCP스택과 사용자 버퍼간에 일어나는 복사를 생략하여
성능을 향상 시킬 수 있다. 그러나 이렇게 하기 위해서는 사용자 버퍼가 오버랩드
수행이 이뤄지는 동안 그리고 오버랩드 수행이 끝나기 전까지는 그 사용자 버퍼를
접근(access)해서는 안될 것이다.

오버랩드 수행이 완료되었는지 알기 위해서는 다음과 같은 방법이 있을수 있다.
1. WSAOVERLAPPED구조체 안에 hEvent 핸들을 써서 이벤트 핸들이 signal될때까지
   기다린다.
2. GetOverlappedResult또는 WSAGetOverlappedResult를 이용하여 오버랩드 I/O
   수행 상태를 계속 체크해 볼 수 있다.(poll) NT의 경우 WSAOVERLAPPED 구조체내의
   hEvent를 NULL로 줘도 되지만, 95에서는 오버랩드 구조체에서는 사용자에 의해
   리셋되는 이벤트 핸들이 필요하다. ( maual reset event handle )
3. ReadFileEx, WriteFileEx, WSARecv, WSARecvFrom, WSASend, WSASendTo함수들은
   I/O 작업이 완료되면 이를 위해 설정했던 완료함수가 호출된다. 만일 완료함수가
   호출되게끔 하려면 오버랩드 I/O 수행을 시작한 이후 Win32 Wait 함수나 WSA 버전
   의 Wait 함수를 써서 non-signal인 핸들인 상태에서 I/O작업을 호출한 스레드가
   alertable wait state( 깨울수 있는 대기 상태 )로 놓아야 한다.
   Overlapped I/O 수행이 끝나면 완료 함수가 호출되고, wait 시키는 함수(SleepEx 같은것)는
   WAIT_IO_COMPLETION을 리턴하고, I/O 작업을 호출했던 스레드는 잠에서 깨어나
   다음 코드를 진행 하게 된다. (wake up)
4. Overlapped I/O 속성이 있으면, GetQueuedCompletionStatus와 associate a socket를
   이용한 Windows NT I/O Completio Port( IOCP )를 이용할 수 있다.
   IOCP를 이용하면 완료 함수를 작성하지 않아도 되며, 시그널되기 위한 이벤트 핸들을
   wait 시킬 필요도 없으며, Overlapped 수행의 상태를 계속 감시(poll)할 필요도없다.
   IOCP를 쓰게되면 오버랩드 소켓핸들은 IOCP에 추가되고 I/O API함수들 ( recv, recvfrom,
   send, sendto를 제외한 Read/WriteFile 등 함수 및 WSASend/Recv 관련 함수들)을 이용해
   오버랩드 수행을 할 수 있다. I/O 완료 패킷을 얻기 위해 GetQueuedCompletionStatus
   API에 의한 wait에 의해 작업용 워커 스레드를 블럭시키게 된다. Overlapped I/O가 완료
   되면 I/O Completion Packet이 GetQueuedCompletionStatus에서 리턴되게 된다.
   Windows NT에서 제공되는 IOCP를 이용하면 확장성있고 높은 수준의 서버 성능을 매우
   간단한 스레딩 코드와 블러킹 코드만을 이용하여 구현 할 수 있다.

'KB > tutorial' 카테고리의 다른 글

DDK in VC with SoftICE  (1) 2004.11.04
COM 형식 라이브러리 사용하기  (0) 2004.11.04
snmp 프로그래밍  (0) 2004.03.19
MSN 프로그래밍 하기  (0) 2004.03.19
COM+ 컴포넌트 만들기  (0) 2004.03.19

+ Recent posts