2015년 1월 16일 금요일

TCP/IP 소켓 프로그래밍 22강

21강에서 알아본 비동기는 "알림"이었다.
전송이 완료되면 완료 되었다고 알려주는 것이였다.
22강에서는 IO를 비동기로 처리하는 방법을 설명한다.

22-1 :  Overlapped IO 모델의 이해

-IO(입출력)의 중첩이란?-

하나의 쓰레드 내에서 동시에 둘 이상의영역으로 데이터를 전송(또는 수신)함으로 인해서,
입출력이 중첩되는 상황을 가리켜 "IO의 중첩"이라 한다.
이러한 일이 가능하려면 호출된 입출력 함수가 바로 반환을 해야한다.
비동기 IO가 가능하려면 호출되는 입출력함수는  넌-블로킹 모드로 동작해야 한다.
윈도우에서 말하는 Overlapped IO는 입출력만을 뜻하는 것이 아니고
입출력의 완료를 확인하는 방법까지 포함한 것이다.

-Overlapped IO 소켓의 생성-

#include <winsock2.h>
SOCKET WSASocket ( int af, int type, int protocol,
               LPWSAPROTOCOL_INFO lpProtocolInfo, GROUP g, DWORD dwFlags);
->성공시 소켓의 핸들, 실패시 INVALID_SOCKET 반환

- af : 프로토콜 체계 정보 전달
- type : 소켓의 데이터 전송방식에 대한 정보 전달
-protocol : 두 소켓 사이에 사용되는 프로토콜 정보 전달
-lpProtocolInfo : 생성되는 소켓의 특성정보를 담고 있는 WSAPROTOCOL_INFO 구조체
                         변수의 주소 값 전달, 필요 없는 경우 NULL 전달
- g : 함수의 확장을 위해서 예약되어 있는 매개변수, 따라서 0 전달
- dwFlags : 소켓의 속성정보 전달

-Overlapped IO를 진행하는 WSASend 함수-

데이터의 입출력의 사용되는 함수는 달리해야 한다.
데이터 출력 함수를 보자

#include <winsock2.h>
int WSASend (SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
                     LPDWORD lpNumberOfBytesSent, DWORD dwFlags,
                     LPWSAOVERLAPPED lpOverlapped,
                     LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
-> 성공시 0, 실패시 SOCKET_ERROR 반환

- s : 소켓의 핸들 전달, Overlapped  IO 속성이 부여된 소켓의 핸들 전달시
        Overlapped IO 모델로 출력 진행
- lpBuffers : 전송할 데이터 정보를 지니는 WSABUF 구조체 변수들로
                   이뤄진 배열의 주소 값 전달
- dwBufferCount : 두 번째 인자로 전달된 배열의 길이정보 전달
- lpNumberOfBytesSent : 전송된 바이트 수가 저장될 변수의 주소 값 전달
-dwFlags : 함수의 데이터 전송특성을 변경하는 경우에 사용
- lpOverlapped : WSAOVERLAPPED 구조체 변수의 주소 갑 전달,
                       이벤트 오브젝트를 사용해서
                       데이터 전송의 완료를 확인하는 경우에 사용되는 매개변수
- lpCompletionRoutine : Completion Routine 이라는 함수의 주소 값 전달,
                                   이를 통해서도 데이터 전송의 완료를 확인할 수 있다.

주의할 점이 있다. Overlapped IO를 진행하려면 WSASend 함수의 매개변수 lpOverlapped에는 항상 NULL이 아닌, 유효한 구조체 변수의 주소 값을 전달해야 한다.
만약에 lpOverlapped에 NULL 이 전달되면, WSASend 함수의 첫 번째 인자로 전달된 핸들의 소켓은 블로킹 모드로 동작하는 일반적인 소켓으로 간주된다.

WSASend 함수는 SOCKET_ERROR를 반환하고, WSAGetLastError 함수 호출을 통해서 확인 가능한 오류코드로는 WSA_IO_PENDING이 등록된다. 그리고 이 경우에는 다음 함수호출을 통해서 실제 전송된 데이터의 크기를 확인해야 한다.

#include <winsock2.h>
BOOL WSAGetOverlappedResult (SOCKET s, LPWSAOVERLAPPED lpOverlapped,
                                  LPDWORD lpcbTransfer, BOOL fWait, LPDWORD lpdwFlags);
-> 성공시 TRUE, 실패시 FALSE 반환

-s : Overlapped IO가 진행된 소켓의 핸들
-lpOverlapped : Overlapped IO 진행시 전달한
                        WSAOVERLAPPED 구조체 변수의 주소값 전달
-lpcbTransfer : 실제 송수신된 바이트 크기를 저장할 변수의 주소 값 전달
-fWait : 여전히 IO가 진행중인 상황의 경우,
            TRUE 전달시 IO가 완료될 때까지 대기를 하게 되고,
            FALSE 전달 시 FALSE를 반환하면서 함수를 빠져 나온다.
-lpdwFlags : WSARecv 함수가 호출된 경우, 부수적인 정보를 얻기 위해 사용된다.
                   불필요하면 NULL 를 전달한다.

-Overlapped IO를 진행하는 WSARecv 함수-

#include <winsock2.h>
int WSARecv ( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
                     LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags,
                     LPWSAOVERLAPPED lpOverlapped,
                     LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );
-> 성공 시 0, 실패시 SOCKET_ERROR 반환

- s : Overlapped IO 속성이 부여된 소켓의 핸들 전달
- lpBuffers : 수신된 데이터 정보가 저장될 버퍼의 정보를 지니는
                   WSABUF 구조체 배열의 주소 값 전달
- dwBufferCount : 두 번째 인자로 전달된 배열의 길이정보 전달
- lpNumberOfBytesRecvd : 수신된 데이터의 크기정보가 저장될 변수의 주소 값 전달
- lpFlags : 전송특성과 관련된 정보를 지정하거나 수신하는 경우에 사용된다.
- lpOverlapped : WSAOBERLAPPED 구조체 변수의 주소 값 전달
- lpCompletionRoutine : Completion Routine 이라는 함수의 주소 값 전달

22-1 : Overlapped IO에서의 입출력 완료의 확인

입출력의 완료/결과를 확인하는 방법에는 두 가지가 있다.
(1)WSASend, WSARecv 함수의 6번째 매개 변수 활용방법, 이벤트 오브젝트 기반
(2)WSASend, WSARecv 함수의 7번째 매개 변수 활용방법, Completion Routine기반

-이벤트 오브젝트 사용하기-

-IO가 완료되면 WSAOVERLAPPED 구조체 변수가 참조하는 이벤트 오브젝트가 signaled 상태가 된다.
-IO의 완료 및 결과를 확인하려면 WSAGetOverlappedResult 함수를 사용한다.

-Completion Routine 사용하기-

역시 소스를 여기에 기재해야하는데 공간이 부족하니 다운 받아서 확인해보는 것이 좋다.
그리고 윈도우는 뭔 이름이 이리 긴지 모르겠다 ㅡㅡ

소스 코드 다운 받기

댓글 없음:

댓글 쓰기