본문 바로가기

IT노트(구)/C/C++

초간단 IOCP 예제(서버/클라이언트)

초간단 IOCP 예제를 소개한다!(서버/클라이언트)

잘 동작하는 소스이므로 참고 자료로 사용하면 좋을 것 같다!(그대로 복사해서 빌드를 하면 된다!)


1. IOCP 서버

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <process.h>
 
#define BUFSIZE 1024
 
typedef struct
{
    SOCKET hClntSock;
    SOCKADDR_IN clntAddr;
} PER_HANDLE_DATA, *LPPER_HANDLE_DATA;
 
typedef struct
{
    OVERLAPPED overlapped;
    char buffer[BUFSIZE];
    WSABUF wsaBuf;
} PER_IO_DATA, *LPPER_IO_DATA;
 
unsigned int __stdcall CompletionThread(LPVOID pComPort);
void ErrorHandling(char *message);
 
#pragma comment(lib, "ws2_32.lib")
 
int main(int argc, char** argv)
{
    WSADATA wsaData;
    if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
        ErrorHandling("WSAStartup() error!");
 
    HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 00);
 
    SYSTEM_INFO SystemInfo;
    GetSystemInfo(&SystemInfo);
    for(int i=0; i<SystemInfo.dwNumberOfProcessors; ++i)
        _beginthreadex(NULL, 0, CompletionThread, (LPVOID)hCompletionPort, 0, NULL);
 
    SOCKET hServSock = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
 
    SOCKADDR_IN servAddr;
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    //servAddr.sin_port = htons(atoi("2738"));
    servAddr.sin_port = htons(2738);
 
    bind(hServSock, (SOCKADDR*)&servAddr, sizeof(servAddr));
    listen(hServSock, 5);
 
    LPPER_IO_DATA PerIoData;
    LPPER_HANDLE_DATA PerHandleData;
 
    int RecvBytes;
    int i, Flags;
 
    while(TRUE)
    {
        SOCKADDR_IN clntAddr;
        int addrLen = sizeof(clntAddr);
 
        SOCKET hClntSock = accept(hServSock, (SOCKADDR*)&clntAddr, &addrLen);
 
        PerHandleData = (LPPER_HANDLE_DATA)malloc(sizeof(PER_HANDLE_DATA));
        PerHandleData->hClntSock = hClntSock;
        memcpy(&(PerHandleData->clntAddr), &clntAddr, addrLen);
 
        CreateIoCompletionPort((HANDLE)hClntSock, hCompletionPort, (DWORD)PerHandleData, 0);
 
        PerIoData = (LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));
        memset(&(PerIoData->overlapped), 0sizeof(OVERLAPPED));
        PerIoData->wsaBuf.len = BUFSIZE;
        PerIoData->wsaBuf.buf = PerIoData->buffer;
        Flags = 0;
 
        WSARecv(PerHandleData->hClntSock, &(PerIoData->wsaBuf), 1, (LPDWORD)&RecvBytes, (LPDWORD)&Flags, &(PerIoData->overlapped), NULL);
    }
 
    return 0;
}
 
unsigned int __stdcall CompletionThread(LPVOID pComPort)
{
    HANDLE hCompletionPort = (HANDLE)pComPort;
    DWORD BytesTransferred;
    LPPER_HANDLE_DATA PerHandleData;
    LPPER_IO_DATA PerIoData;
    DWORD flags;
 
    while(1) {
        GetQueuedCompletionStatus(hCompletionPort, &BytesTransferred, (LPDWORD)&PerHandleData, (LPOVERLAPPED*)&PerIoData, INFINITE);
 
        if(BytesTransferred == 0)
        {
            closesocket(PerHandleData->hClntSock);
            free(PerHandleData);
            free(PerIoData);
            continue;
        }
 
        PerIoData->wsaBuf.buf[BytesTransferred] = '\0';
        printf("Recv[%s]\n", PerIoData->wsaBuf.buf);
 
        PerIoData->wsaBuf.len = BytesTransferred;
        WSASend(PerHandleData->hClntSock, &(PerIoData->wsaBuf), 1, NULL, 0, NULL, NULL);
 
        memset(&(PerIoData->overlapped), 0sizeof(OVERLAPPED));
        PerIoData->wsaBuf.len = BUFSIZE;
        PerIoData->wsaBuf.buf = PerIoData->buffer;
 
        flags = 0;
 
        WSARecv(PerHandleData->hClntSock, &(PerIoData->wsaBuf), 1, NULL, &flags, &(PerIoData->overlapped), NULL);
    }
 
    return 0;
}
 
void ErrorHandling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}
cs


2. IOCP 클라이언트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
 
void ErrorHandling(char *message);
 
#pragma comment(lib, "ws2_32.lib")
 
int main()
{
    WSADATA wsaData;
    if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
        ErrorHandling("WSAStartup() error!");
 
    SOCKET hSocket = WSASocket(PF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
    if(hSocket == INVALID_SOCKET)
        ErrorHandling("socket() error");
 
    SOCKADDR_IN recvAddr;
    memset(&recvAddr, 0sizeof(recvAddr));
    recvAddr.sin_family = AF_INET;
    recvAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    recvAddr.sin_port = htons(2738);
 
    if(connect(hSocket, (SOCKADDR*)&recvAddr, sizeof(recvAddr)) == SOCKET_ERROR)
        ErrorHandling("connect() error!");
 
    WSAEVENT event = WSACreateEvent();
 
    WSAOVERLAPPED overlapped;
    memset(&overlapped, 0sizeof(overlapped));
 
    overlapped.hEvent = event;
 
    WSABUF dataBuf;
    char message[1024= {0,};
    int sendBytes = 0;
    int recvBytes = 0;
    int flags = 0;
 
    while(true)
    {
        flags = 0;
        printf("전송할데이터(종료를원할시exit)\n");
 
        scanf("%s", message);
 
        if(!strcmp(message, "exit")) break;
 
        dataBuf.len = strlen(message);
        dataBuf.buf = message;
 
        if(WSASend(hSocket, &dataBuf, 1, (LPDWORD)&sendBytes, 0, &overlapped, NULL) == SOCKET_ERROR)
        {
            if(WSAGetLastError() != WSA_IO_PENDING)
                ErrorHandling("WSASend() error");
        }
 
        WSAWaitForMultipleEvents(1, &event, TRUE, WSA_INFINITE, FALSE);  
 
        WSAGetOverlappedResult(hSocket, &overlapped, (LPDWORD)&sendBytes, FALSE, NULL);
 
        printf("전송된바이트수: %d \n", sendBytes);
 
        if(WSARecv(hSocket, &dataBuf, 1, (LPDWORD)&recvBytes, (LPDWORD)&flags, &overlapped, NULL) == SOCKET_ERROR)
        {
            if(WSAGetLastError() != WSA_IO_PENDING)
                ErrorHandling("WSASend() error");
        }
 
        printf("Recv[%s]\n",dataBuf.buf);
    }
 
    closesocket(hSocket);
 
    WSACleanup();
 
    return 0;
}
 
void ErrorHandling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
 
    exit(1);
}
cs


출처 : http://cafe.naver.com/boolnim/403