IOCP에서의 IO의 완료 확인
- IOCP에서는 완료된 IO를 관리하기 위해 Completion Port 오브젝트 사용
- CP를 사용하기 위해서는 아래의 단계 수행
1. Completion Port 생성
2. Completion Port에 소켓을 등록
3. IO가 완료되면 Completion Port에 등록
4. 등록된 정보를 확인해서 처리
IOCP 관련 함수
- CreateIoCompletionPort : CP 오브젝트 생성 및 소켓을 CP에 등록하는 함수
-> FileHandle : 소켓 핸들 전달
-> ExistingCompletionPort : CP 전달
-> CompletionKey : 전달되는 인자 값
-> NumberOfConcurrentThread : CP 오브젝트에 할당되어 완료된 IO를 동시에 처리할 수 있는 쓰레드의 수 전달. 0 전달 시 동시에 실행 가능한 최대 수
HANDLE CreateIoCompletionPort (HANDLE FileHandle, HANDLE ExistingCompletionPort,
ULONG_PTR CompletionKey, DWORD NumberOfConcurrentThreads);
-> CP 오브젝트 생성 시
hComPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
-> 클라이언트 소켓 등록
typedef struct // socket info
{
SOCKET hClntSock;
SOCKADDR_IN clntAdr;
} PER_HANDLE_DATA, *LPPER_HANDLE_DATA;
LPPER_HANDLE_DATA handleInfo;
hClntSock=accept(hServSock, (SOCKADDR*)&clntAdr, &addrLen);
handleInfo=(LPPER_HANDLE_DATA)malloc(sizeof(PER_HANDLE_DATA));
handleInfo->hClntSock=hClntSock;
memcpy(&(handleInfo->clntAdr), &clntAdr, addrLen);
CreateIoCompletionPort((HANDLE)hClntSock, hComPort, (DWORD)handleInfo, 0);
- GetQueuedCompletionStatus : 완료된 IO를 확인
-> CompletionPort : 완료된 IO가 등록된 CP 핸들 전달
-> lpNumberOfBytes : 송수신된 데이터의 크기를 저장할 변수 주소
-> lpCompletionKey : CreateIoCompletionPort에서 등록한 정보
-> lpOverlapped : WSASend, WSARecv 시 전달한 OVERLAPPED 구조체
-> dwMilliseconds : 타임아웃 정보. INFINITE 전달 시 완료된 IO가 CP에 등록될 때까지 블로킹 상태로 대기
BOOL GetQueuedCompletionStatus (HANDLE CompletionPort, LPDWORD lpNumberOfBytesTransferred,
PULONG_PTR lpCompletionKey, LPOVERLAPPED *lpOverlapped, DWORD dwMilliseconds);
IOCP 기반의 에코 서버
int main(int argc, char* argv[])
{
HANDLE hComPort;
SYSTEM_INFO sysInfo;
LPPER_IO_DATA ioInfo;
LPPER_HANDLE_DATA handleInfo;
...;
hComPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
// CP 생성
GetSystemInfo(&sysInfo);
// 시스템 정보
for(i=0; i<sysInfo.dwNumberOfProcessors; i++)
_beginthreadex(NULL, 0, EchoThreadMain, (LPVOID)hComPort, 0, NULL);
// 프로세서 개수만큼 쓰레드 생성 시 CP전달
hServSock=WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
...;
while(1)
{
SOCKET hClntSock;
SOCKADDR_IN clntAdr;
int addrLen=sizeof(clntAdr);
hClntSock=accept(hServSock, (SOCKADDR*)&clntAdr, &addrLen);
handleInfo=(LPPER_HANDLE_DATA)malloc(sizeof(PER_HANDLE_DATA));
handleInfo->hClntSock=hClntSock;
memcpy(&(handleInfo->clntAdr), &clntAdr, addrLen);
// 연결된 클라이언트 정보
CreateIoCompletionPort((HANDLE)hClntSock, hComPort, (DWORD)handleInfo, 0);
// 연결된 클라이언트 소켓 등록 시 정보도 전달
ioInfo=(LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));
memset(&(ioInfo->overlapped), 0, sizeof(OVERLAPPED));
ioInfo->wsaBuf.len=BUF_SIZE;
ioInfo->wsaBuf.buf=ioInfo->buffer;
ioInfo->rwMode=READ;
// 처리할 때 사용할 정보들 등록
WSARecv(handleInfo->hClntSock, &(ioInfo->wsaBuf),
1, &recvBytes, &flags, &(ioInfo->overlapped), NULL);
}
return 0;
}
DWORD WINAPI EchoThreadMain(LPVOID pComPort)
{
HANDLE hComPort=(HANDLE)pComPort; // 인자로 전달된 CP
SOCKET sock;
DWORD bytesTrans;
LPPER_HANDLE_DATA handleInfo;
LPPER_IO_DATA ioInfo;
DWORD flags=0;
while(1)
{
GetQueuedCompletionStatus(hComPort, &bytesTrans,
(LPDWORD)&handleInfo, (LPOVERLAPPED*)&ioInfo, INFINITE);
// 완료된 IO에 대한 정보를 얻어옴
sock=handleInfo->hClntSock;
if(ioInfo->rwMode==READ)
{
if(bytesTrans==0) // EOF 전송 시
{
closesocket(sock);
free(handleInfo); free(ioInfo);
continue;
}
memset(&(ioInfo->overlapped), 0, sizeof(OVERLAPPED));
ioInfo->wsaBuf.len=bytesTrans;
ioInfo->rwMode=WRITE;
WSASend(sock, &(ioInfo->wsaBuf),
1, NULL, 0, &(ioInfo->overlapped), NULL);
// Send
ioInfo=(LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));
memset(&(ioInfo->overlapped), 0, sizeof(OVERLAPPED));
ioInfo->wsaBuf.len=BUF_SIZE;
ioInfo->wsaBuf.buf=ioInfo->buffer;
ioInfo->rwMode=READ;
WSARecv(sock, &(ioInfo->wsaBuf),
1, NULL, &flags, &(ioInfo->overlapped), NULL);
// Send 후 다시 Recv 호출하여 수신 대기
} // 수행한 IO가 READ 였다면
else
{
puts("message sent!");
free(ioInfo);
} // 수행한 IO가 SEND 였다면
}
return 0;
}
'Programming > Network' 카테고리의 다른 글
OSI 7 계층 (0) | 2021.07.21 |
---|---|
열혈 TCP/IP 소켓 프로그래밍 정리(完) (0) | 2021.04.27 |
열혈 TCP/IP 23-1. Overlapped IO를 기반으로 IOCP 이해하기 (0) | 2021.04.25 |
열혈 TCP/IP 22-2. Overlapped IO에서의 입출력 완료의 확인 (0) | 2021.04.25 |
열혈 TCP/IP 22-1. Overlapped IO 모델의 이해 (0) | 2021.04.25 |