Post

반응형

아래의 기본 서버 예제는 문제점이 있다.

클라이언트가 많아지면 접속을 제 때 받지 못한다.

또 처리하는 부분(send)도 시간이 많이 걸리면 클라이언트 접속 대기 시간이 생긴다.

둘 다 분리되어있지 않고, 원스레드에서 해결하기 때문이다.

아래는 원스레드 서버의 처리시간이 길어지면 어떤문제점이 있는지 보여주는 예제이다.


상황설정

서버는 원스레드로, 클라이언트 접속 후에 1초걸리는 일을 처리하고 패킷을 전달한다.

클라이언트는 배치 파일을 만들어서 7개가 동시에 Connect를 요청하고 서버의 응답을 기다린다.


bat 파일은 아래와 같이 작성했다.

( ConsoleApplication2.exe 가 클라이언트다.. .;; )

 start /d "C:\Users\MyDirectory\Documents\Visual Studio 2017\ConsoleApplication2\Debug\" ConsoleApplication2.exe

 start /d "C:\Users\MyDirectory\Documents\Visual Studio 2017\ConsoleApplication2\Debug\" ConsoleApplication2.exe

 start /d "C:\Users\MyDirectory\Documents\Visual Studio 2017\ConsoleApplication2\Debug\" ConsoleApplication2.exe

 start /d "C:\Users\MyDirectory\Documents\Visual Studio 2017\ConsoleApplication2\Debug\" ConsoleApplication2.exe

 start /d "C:\Users\MyDirectory\Documents\Visual Studio 2017\ConsoleApplication2\Debug\" ConsoleApplication2.exe

 start /d "C:\Users\MyDirectory\Documents\Visual Studio 2017\ConsoleApplication2\Debug\" ConsoleApplication2.exe

 start /d "C:\Users\MyDirectory\Documents\Visual Studio 2017\ConsoleApplication2\Debug\" ConsoleApplication2.exe

<server> 

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
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
 
#define BUF_SIZE 30
 
void ErrorHandling(const char* message);
 
int main()
{
    WSADATA wsaData;
    SOCKET hServSock, hClntSock;
    SOCKADDR_IN servAddr, clntAddr;
    int strLen = 0;
 
    int szClntAddr;
    char message[] = "Hello World!";
    
    if (0 != WSAStartup(MAKEWORD(22), &wsaData))
    {
        ErrorHandling("WSAStartup() error!");
    }
 
    hServSock = socket(PF_INET, SOCK_STREAM, 0);
    if (INVALID_SOCKET == hServSock)
        ErrorHandling("socket() error");
 
    memset(&servAddr, 0sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port = htons(atoi("8888"));
 
    if (SOCKET_ERROR == bind(hServSock, (SOCKADDR*)&servAddr, sizeof(servAddr)))
    {
        ErrorHandling("bind error \n");
    }
 
    if(SOCKET_ERROR == listen(hServSock, 5))
    {
        ErrorHandling("listen error \n");
    }
 
    szClntAddr = sizeof(clntAddr);
    int i = 0;
    while(true)
    {
        hClntSock = accept(hServSock, (SOCKADDR*)&clntAddr, &szClntAddr);
        if (-1 == hClntSock)
        {
            ErrorHandling("accept() error \n");
        }
        else
        {
            printf("Connected clinet : %d \n", i + 1);
        }
        ++i;
        Sleep(1000);
 
        send(hClntSock, message, BUF_SIZE, 0);
 
        closesocket(hClntSock);
    }
    
    closesocket(hServSock);
    WSACleanup();
 
    return 0;
}
 
void ErrorHandling(const char* message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}
cs


<Client>

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
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <ws2tcpip.h>
#include <windows.h>
 
#define BUF_SIZE 30
void ErrorHandling(const char* message);
 
int main()
{
    WSADATA wsaData;
    SOCKET hSocket;
    SOCKADDR_IN servAddr;
    char message[30];
    int strLen;
 
    if (0 != WSAStartup(MAKEWORD(22), &wsaData))
    {
        ErrorHandling("WSAStartup() error!");
    }
 
    hSocket = socket(PF_INET, SOCK_STREAM, 0);
    if (INVALID_SOCKET == hSocket)
    {
        ErrorHandling("WSAStartup() error!");
    }
    
    memset(&servAddr, 0sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    //servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    inet_pton(AF_INET, "127.0.0.1"&servAddr.sin_addr);
    servAddr.sin_port = htons(atoi("8888"));
 
    if(SOCKET_ERROR == connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr)))
    {
        printf("error:%d \n", WSAGetLastError());
        ErrorHandling("connect() error");
    }
    else
    {
        puts("Connected......");
    }
    
    int beginTime = GetTickCount();        
    strLen = recv(hSocket, message, BUF_SIZE - 10);
    int endTime = GetTickCount();
    int passTime = endTime - beginTime;
    message[strLen] = 0;
    printf("Message from server ms:%d second:%f message:%s \n", passTime, (passTime * 0.001), message);
 
    closesocket(hSocket);
    WSACleanup();        
 
    system("pause");
    return 0;
}
 
void ErrorHandling(const char* message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}
cs


<결과>

서버는 1초짜리 일을 했지만 접속순서대로 차례대로 일을 처리했기 때문에,

후순위로 Connect한 클라이언트는 5~6초나 지나서 결과를 받았다.

멀티스레드 서버를 사용해야하는 이유다.

 


반응형
▲ top