티스토리 뷰

프로그래밍/C++

TCP 클라이언트, 서버

에어버스 2022. 11. 13. 15:50

한 PC 안에서 서버와 클라이언트 실행하여 테스트 함.

TimeServer.zip
0.59MB

 

TimeClient.zip
0.62MB

서버

순차 서버
서버의 시간을 알려주는것과 같이 서버의 응답시간이 짧은 경우 순차 서버로 구현한다.

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
#include <iostream>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <time.h>
 
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable : 4996// inet_ntoa 경고 무시
 
 
int main(void)
{
    WSADATA wsaData;
    BYTE nMajor = 2, nMinor = 2;
    WORD wVersionRequested = MAKEWORD(nMinor, nMajor);
    int nRet = WSAStartup(wVersionRequested, &wsaData);
    if (nRet == SOCKET_ERROR)
    {
        std::cout << "윈도우 소켓을 초기화 할 수 없습니다." << std::endl;
        return -1;
    }
 
    if (LOBYTE(wsaData.wVersion) != nMajor || HIBYTE(wsaData.wVersion) != nMinor)
    {
        std::cout << "윈도우 소켓 " << nMajor << "." << nMinor << "을 사용할 수 없습니다." << std::endl;
        WSACleanup();
        return -1;
    }
 
    SOCKET lstnsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    try {
        if (lstnsock == INVALID_SOCKET)
            throw "대기 소켓 객체 생성 실패";
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(42001);
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        if (bind(lstnsock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
            throw "bind 에러";
        if (listen(lstnsock, SOMAXCONN) == SOCKET_ERROR)
            throw "listen 에러";
        while (1)
        {
            struct sockaddr_in cliaddr;
            int addrlen = sizeof(cliaddr);
            PVOID pAddr = (PVOID)&cliaddr.sin_addr;
            CHAR szAddr[NI_MAXHOST] = { 0 };
 
            SOCKET commsock = accept(lstnsock, (struct sockaddr*)&cliaddr, &addrlen);
            std::cout << "[" << inet_ntoa(cliaddr.sin_addr) << "]";     
            std::cout << "로 부터 접속" << std::endl;
            time_t long_time;
            struct tm* newtime = NULL;
            char sztime[100];
 
            time(&long_time);
            newtime = localtime(&long_time);
            sprintf_s(sztime, "%.19s\n", asctime(newtime));
            send(commsock, sztime, (int)strlen(sztime), 0);
            closesocket(commsock);
        }
    }
    catch (char* errmsg)
    {
        std::cout << errmsg << std::endl;
        LPVOID lpOSMsg;
        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, WSAGetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpOSMsg, 0NULL);
        std::cout << "[" << (char*)lpOSMsg << "]" << std::endl;
        LocalFree(lpOSMsg);
    }
    if (lstnsock != INVALID_SOCKET)
        closesocket(lstnsock);
    WSACleanup();
    return 0;
}
cs

클라이언트

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
#include <iostream>
#include <WinSock2.h>
#include <WS2tcpip.h>
 
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable : 4996// inet_addr 경고 무시
 
int main(void)
{
    WSADATA wsaData;
    BYTE nMajor = 2, nMinor = 2;
    WORD wVersionRequested = MAKEWORD(nMinor, nMajor);
    int nRet = WSAStartup(wVersionRequested, &wsaData);
    if (nRet == SOCKET_ERROR)
    {
        std::cout << "윈도우 소켓을 초기화 할 수 없습니다." << std::endl;
        return -1;
    }
    if (LOBYTE(wsaData.wVersion) != nMajor || HIBYTE(wsaData.wVersion) != nMinor)
    {
        std::cout << "윈도우 소켓 " << nMajor << "." << nMinor << "을 사용할 수 없습니다." << std::endl;
        WSACleanup();
        return -1;
    }
    char szip[30];
    std::cout << "접속할 서버 주소를 입력하세요 : ";
    std::cin >> szip;
 
    SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    try {
        if (sock == INVALID_SOCKET)
            throw "소켓 객체 생성 실패";
 
        CHAR szAddr[NI_MAXHOST] = { 0 };
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(42001);
        addr.sin_addr.s_addr = inet_addr(szip);
        if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
            throw "connect 에러";
        char sztime[100= { 0 };
        recv(sock, sztime, sizeof(sztime), 0);
        std::cout << "서버의 시간 : " << sztime << std::endl;
    }
    catch (char* errmsg)
    {
        std::cout << errmsg << std::endl;
        LPVOID lpOSMsg;
        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, WSAGetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpOSMsg, 0NULL);
        std::cout << "[" << (char*)lpOSMsg << "]" << std::endl;
        LocalFree(lpOSMsg);
    }
    if (sock != INVALID_SOCKET)
        closesocket(sock);
    WSACleanup();
    return 0;
}
cs

 

서버 실행화면

클라이언트 실행화면

한 PC 안에서 서버와 클라이언트 실행하여 테스트 함.

 

병렬 서버
서버의 시간을 알려주는 것과 같이 서버의 응답시간일 짧은것은 순서 서버로 가능하지만 서버의 처리 시간이 길어 응답 시간이 늦은 경우 병렬 서버로 TCP 서버를 구현해야 한다.
순차 서버와 코드는 같지만 응답 시간이 길어지는 작업을 스레드로 만든다. (9~24행)

실행화면은 위 그림과 같다.

TimeServer.zip
0.66MB

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
#include <iostream>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <time.h>
 
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable : 4996// inet_ntoa 경고 무시
 
DWORD WINAPI CommThread(LPVOID pvoid)
{
    SOCKET commsock = (SOCKET)pvoid;
 
    time_t long_time;
    struct tm* newtime = NULL;
    char sztime[100];
 
    time(&long_time);
    newtime = localtime(&long_time);
    sprintf_s(sztime, "%.19s\n", asctime(newtime));
    send(commsock, sztime, (int)strlen(sztime), 0);
    closesocket(commsock);
    
    return 0;
}
 
int main(void)
{
    WSADATA wsaData;
    BYTE nMajor = 2, nMinor = 2;
    WORD wVersionRequested = MAKEWORD(nMinor, nMajor);
    int nRet = WSAStartup(wVersionRequested, &wsaData);
    if (nRet == SOCKET_ERROR)
    {
        std::cout << "윈도우 소켓을 초기화 할 수 없습니다." << std::endl;
        return -1;
    }
 
    if (LOBYTE(wsaData.wVersion) != nMajor || HIBYTE(wsaData.wVersion) != nMinor)
    {
        std::cout << "윈도우 소켓 " << nMajor << "." << nMinor << "을 사용할 수 없습니다." << std::endl;
        WSACleanup();
        return -1;
    }
 
    SOCKET lstnsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    try {
        if (lstnsock == INVALID_SOCKET)
            throw "대기 소켓 객체 생성 실패";
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(42001);
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        if (bind(lstnsock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
            throw "bind 에러";
        if (listen(lstnsock, SOMAXCONN) == SOCKET_ERROR)
            throw "listen 에러";
        while (1)
        {
            struct sockaddr_in cliaddr;
            int addrlen = sizeof(cliaddr);
            PVOID pAddr = (PVOID)&cliaddr.sin_addr;
            CHAR szAddr[NI_MAXHOST] = { 0 };
 
            SOCKET commsock = accept(lstnsock, (struct sockaddr*)&cliaddr, &addrlen);
            std::cout << "[" << inet_ntoa(cliaddr.sin_addr) << "]";     
            std::cout << "로 부터 접속" << std::endl;
            
            HANDLE hThread = CreateThread(NULL0, CommThread, (LPVOID)commsock, 0NULL);
            CloseHandle(hThread);
        }
    }
    catch (char* errmsg)
    {
        std::cout << errmsg << std::endl;
        LPVOID lpOSMsg;
        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, WSAGetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpOSMsg, 0NULL);
        std::cout << "[" << (char*)lpOSMsg << "]" << std::endl;
        LocalFree(lpOSMsg);
    }
    if (lstnsock != INVALID_SOCKET)
        closesocket(lstnsock);
    WSACleanup();
    return 0;
}
cs

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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