컴퓨터 공부/네트워크 프로그래밍

[TCP/IP 소켓 프로그래밍] 21. Overlapped 입출력 모델

려리군 2009. 8. 28. 19:39

21-1. Overlapped 입출력의 의미

비중첩 데이터 입출력 모델


중첩된 데이터 입출력 모델

하나의 쓰레드 내에서 여러 개의 입출력이 진행되는 것


21-2. Overlapped 입출력을 위한 기본 단계

1. Overlapped 소켓의 생성

SOCKET WSASocket(

  __in  int af,

  __in  int type,

  __in  int protocol,

  __in  LPWSAPROTOCOL_INFO lpProtocolInfo,

  __in  GROUP g,

  __in  DWORD dwFlags

);

af : address family

type : 소켓 형태

protocol : 사용된 프로토콜(여기까지 socket과 동일)

lpProtocolInfo : 생성될 소켓의 성경을 정의하는 wSAPROTOCOL_INFO 포인터

g : 예약됨.

dwFlags : 소켓 속성을 지정하는 플래그


WSASocket(PF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);

WSA_FLAG_OVERLAPPED는 Overlapped 입출력이 가능하도록 하는 플래그.


2. 데이터 송수신

※ 다음 함수들은 버퍼에 존재하는 데이터를 모아서 한 번에 전송하고(Gather) 수신된 데이터를 여러 버퍼에 나누어 저장(Scatter)하는 Gather/Scatter 입출력을 한다.


int WSASend(

    SOCKET s,                  // 소켓 핸들

    LPWSABUF lpBuffers,    // WSABUF 구조체 배열의 포인터

    DWORD dwBufferCount, // lpBuffers가 가리키는 배열의 크기

    LPDWORD lpNumberOfBytesSent, // 전송된 바이트 수를 저장하기 위한 포인터

    DWORD dwFlags,

    LPWSAOVERLAPPED lpOverlapped,

    LPWSAOVERLAPPED_COMPLETION_ROUTING lpCompletionRoutine

);

리턴 : 성공시 0, 실패시 SOCKET_ERROR


typedef struct __WSABUF{

    u_long len;

    char FAR *buf;

}WSABUF, FAR* LPWSABUF;


int WSARecv(

    SOCKET s,                  // 소켓 핸들

    LPWSABUF lpBuffers,    // 수신 버퍼 정보를 지니는WSABUF 구조체 배열의 포인터

    DWORD dwBufferCount, // lpBuffers가 가리키는 배열의 크기

    LPDWORD lpNumberOfBytesRecvd, // 전송된 바이트 수를 저장하기 위한 포인터

    DWORD dwFlags,

    LPWSAOVERLAPPED lpOverlapped,

    LPWSAOVERLAPPED_COMPLETION_ROUTING lpCompletionRoutine

);

리턴 : 성공시 0, 실패시 SOCKET_ERROR

lpOverlapped : 중첩된 입출력을 하기 위해 사용.


3. 데이터 송수신 완료 확인

이벤트 커널 오브젝트 기반

CALLBACK 함수 기반


21-3. Event 커널 오브젝트 기반의 Overlapped I/O
이벤트 커널 오브젝트 : 데이터 송수신이 되었는지 확인하는 용도로 사용.

WSACreateEvent
typedef struct _WSAOVERLAPPED{
    DWORD Internal;
    DWORD InternalHigh;
    DWORD Offset;
    DWORD OffsetHigh;
    // 위의 4개 변수는 내부적으로 사용.
    WSAEVENT hEvent;    // 이벤트 핸들의 오브젝트를 저장한다.
}WSAOVERLAPPED, *LPWSAOVERLAPPED;

WSAWaitForMultipleEvents 함수는 이벤트가 시그널 되었는 지 확인한다.
WSAGetOverlappedResult(
    SOCKET s,
    LPWSAOVERLAPPED lpOverlapped, // WSASend 혹은 WSARecv 호출시 전달한 OVERLAPPED 구조체
    LPDWORD lpcbTransfer, // 전송된 바이트 수
    BOOL fWait,    // TRUE 전달 시 입출력 완료시까지 블로킹
    LPDWORD lpdwFlags
);
※ 송수신한 바이트수, 에러가 발생하였는가? 의 결과를 알려준다.

1. 소켓 이벤트와 WSAOVERLAPPED 구조체와 연결하는 방법
event = WSACreateEvent();
memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = event;
2. WSAWaitForMultipleEvents 함수 호출
WSAWaitForMultipleEvents(1, &event, TRUE, WSA_INFINITE, FALSE);
3. WSAGetOverlappedResult 함수 호출
WSAGetOverlappedResult(hSocket, &overlapped, &sendBytes, FALSE, NULL);

21-4. Completion Routines 기반의 Overlapped I/O
콜백 함수 : 특정 상황이 되면 시스템에서 의해 호출되는 함수.

LPWSAOVERLAPPED_COMPLETION_ROUTINE : 다음 콜백함수에 대한 포인터
void CALLBACK CompletionROUTINE(
    DWORD dwError,    // 오류 정보 전달 됨.
    DWORD cbTransferred,    // 전송된 바이트 수 전달됨
    LPWSAOVERLAPPED lpOverlapped,    // WSARecv 함수 호출시 전달한 구조체 변수
    DWORD dwFlags
);
콜백함수가 있을지라도 WSAOVERLAPPED 구조체는 전달해 주어야 한다.
그래서 이벤트 커널 오브젝트는 Dummy Object가 된다.

index = WSAWaitForMultipleEvents(1, &event, FALSE, WSA_INFINITE, TRUE);
index가 WAIT_IO_COMPLETION이면 중첩된 입출력이 완료되었다는 뜻.
다른 의미는 오류가 발생함.