서버


1. 서버

-Serv.h

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
#include <iostream>
#include <stdio.h>
#include <functional>
#include <WinSock2.h>
 
#include <queue>
 
 
#include <process.h>
 
#define PORT 5000
 
typedef struct _cliInfo{
    char* msg;
    struct sockaddr_in clientAddr;
}cliInfo;
 
using namespace std;
 
 
 
class Serv{
 
 
public:
 
    WORD wVersionRequested;     //WORD is a 16-bit unsigned interger. 0000(low-order word)0000(high-order word)
    WSADATA wsaData;
    SOCKET sd;
    struct sockaddr_in serverAddr;// clientAddr;
    char* serverIP;
    struct hostent *host;
    char host_name[BUFSIZ];
     
    int sockAddrLen;
    queue<cliInfo*> q;
 
    function<void(Serv*)> userFunc;
     
     
 
    HANDLE msgMutex;
    HANDLE processingEvent;
 
    HANDLE receiveThread;
    DWORD receiveThreadID;
    HANDLE processThread;
    DWORD processThreadID;
 
 
    Serv();
    ~Serv();
    int bindServerSocket();
    static unsigned int WINAPI receive(void* serv);
    static unsigned int WINAPI process(void* serv);
    int startThread();
};

-Serv.cpp

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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include "Serv.h"  
 
using namespace std;
 
int Serv::bindServerSocket(){
     
 
    //UDP형식의 소켓 생성
    //The Internet Protocol version 4 (IPv4) address family.
    //PF: protocol family
    sd = socket(AF_INET, SOCK_DGRAM, 0);
 
    //소켓 생성 오류 처리
    if (sd == INVALID_SOCKET)
    {
        fprintf(stderr, "Could not create socket.\n");
        WSACleanup();
        return 1;
    }
 
 
 
    //server setting
    serverAddr.sin_family=AF_INET; 
    serverAddr.sin_port=htons(PORT);    //convert byte order short data type
    gethostname(host_name, sizeof(host_name));
    //getting server IP by hostname
    host = gethostbyname(host_name);       
    if (host == NULL)
    {
        fprintf(stderr, "Could not get host name.\n");
        closesocket(sd);
        WSACleanup();
        return 1;
    }
    memcpy(&serverAddr.sin_addr, host->h_addr_list[0], host->h_length);       //서버 ip 설정
 
 
 
    //Bind address to socket
    ::bind(sd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr_in));
    if (sd==NULL )
    {
        fprintf(stderr, "Could not bind name to socket.\n");
        closesocket(sd);
        WSACleanup();
        return 1;
    }
 
    // Print out server information
    serverIP=inet_ntoa(serverAddr.sin_addr);
    printf("Server running on %s\n",serverIP);
 
     
 
    return 0;
};
 
unsigned int Serv::receive(void* serv)
{
    char* msg;
    struct sockaddr_in clientAddr;
    cliInfo* cli;
    Serv* server=(Serv*)serv;
    int n;
    char* clientIP;
 
    //get messages from client and put it in the Queue
    do{
 
        msg=(char*)malloc(sizeof(char)*BUFSIZ);
        cli=(cliInfo*)malloc(sizeof(cliInfo));
        memset((void *)cli, '\0', sizeof(cliInfo));
        //server->sockAddrLen=sizeof(server->clientAddr);
        n=recvfrom(server->sd,msg,BUFSIZ,0,(struct sockaddr *)&(clientAddr),&(server->sockAddrLen)); 
        msg[n]='\0';
        clientIP=inet_ntoa(clientAddr.sin_addr);
        cli->clientAddr=clientAddr;
        cli->msg=msg;
 
        if(n!=0){
            printf("gotten messege from %s\n", clientIP );
            printf("message: %s\n", cli->msg );
        }
 
        //mutex lock befor using Queue
        WaitForSingleObject(server->msgMutex,INFINITE);
        __try{
            server->q.push(cli);
        }
        __finally{
            //mutex unlock
            ReleaseMutex(server->msgMutex);
        }
 
        //set the event signaled after putting msg into the queue
        SetEvent(server->processingEvent);
    }while(strcmp(msg, "quitserver")!=0);
 
    return 0;
}
 
//큐에 있는 메세지를 user defined funtion으로 처리
unsigned int Serv::process(void* serv){
    Serv* server=(Serv*)serv;
    //WaitForSingleObject(server->receiveThread,INFINITE);
    //while(WaitForSingleObject(server->receiveThread,INFINITE)==WAIT_OBJECT_0){
     
    while(1){
        //event가 signaled 상태가 될때까지 기다림
        WaitForSingleObject(server->processingEvent,INFINITE);
 
        //event가 signaled 상태가 된 후 user defined funtion실행
        server->userFunc(server);
 
        //메세지 큐가 비어있으면 event를 nonsignaled 상태로 바꿔줌
        if(server->q.empty())
            ResetEvent(server->processingEvent);
         
    }
    return 0;
}
 
//thread를 실행
int Serv::startThread(){
    receiveThread=(HANDLE)_beginthreadex(NULL,0,Serv::receive,(void*)this,0,(unsigned*)&receiveThreadID);
    processThread=(HANDLE)_beginthreadex(NULL,0,Serv::process,(void*)this,0,(unsigned*)&processThreadID);
    return 0;
}
 
 
Serv::Serv()
{
 
    wVersionRequested=MAKEWORD(2,2);    //window soket 요구 최저버전
    WSAStartup(0x0101, &wsaData);
    msgMutex=CreateMutex(NULL,FALSE,NULL); 
    processingEvent = CreateEvent(
        NULL,               // default security attributes
        TRUE,               // manual-reset event
        FALSE,              // initial state is nonsignaled
        TEXT("ProcessingEvent"// object name
        );
    sockAddrLen=sizeof(sockaddr_in);
}
 
Serv::~Serv()
{
    closesocket(sd);
    WSACleanup();
}
 

-main.cpp(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
#include <iostream>
#include <stdio.h>
#include <functional>
#include <WinSock2.h>
 
#include <queue>
 
 
#include <process.h>
 
#define PORT 5000
 
typedef struct _cliInfo{
    char* msg;
    struct sockaddr_in clientAddr;
}cliInfo;
 
using namespace std;
 
 
 
class Serv{
 
 
public:
 
    WORD wVersionRequested;     //WORD is a 16-bit unsigned interger. 0000(low-order word)0000(high-order word)
    WSADATA wsaData;
    SOCKET sd;
    struct sockaddr_in serverAddr;// clientAddr;
    char* serverIP;
    struct hostent *host;
    char host_name[BUFSIZ];
     
    int sockAddrLen;
    queue<cliInfo*> q;
 
    function<void(Serv*)> userFunc;
     
     
 
    HANDLE msgMutex;
    HANDLE processingEvent;
 
    HANDLE receiveThread;
    DWORD receiveThreadID;
    HANDLE processThread;
    DWORD processThreadID;
 
 
    Serv();
    ~Serv();
    int bindServerSocket();
    static unsigned int WINAPI receive(void* serv);
    static unsigned int WINAPI process(void* serv);
    int startThread();
};


2. 클라이언트


-main.cpp

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
#include <iostream>
#include <WinSock2.h>
#include <stdio.h>
#include <string>
 
 
#define PORT 5000
#pragma comment(lib, "Ws2_32.lib")
int main(){
    SOCKET sd;
    struct sockaddr_in serverAddr, clientAddr;
    char sendline[BUFSIZ];
    char recvline[BUFSIZ];
    char tmp[BUFSIZ];
    char serverIP[BUFSIZ];
    int n,serversize;
    WSADATA w; 
    int check;
     
    if (WSAStartup(0x0101, &w) != 0)
    {
        fprintf(stderr, "Could not open Windows connection.\n");
        exit(0);
    }
    printf("inputIPaddr: ");
    scanf_s("%s",serverIP,sizeof(serverIP));
     
 
 
    sd=socket(AF_INET, SOCK_DGRAM, 0);
 
    memset((void *)&serverAddr, '\0', sizeof(struct sockaddr_in));
    serverAddr.sin_family=AF_INET;
    serverAddr.sin_addr.s_addr=inet_addr(serverIP);
    serverAddr.sin_port=htons(PORT);
 
 
    memset((void *)&clientAddr, '\0', sizeof(struct sockaddr_in));
 
    /* Set family and port */
    clientAddr.sin_family = AF_INET;
    clientAddr.sin_addr.s_addr=INADDR_ANY;
    clientAddr.sin_port = htons(0);
 
    if (bind(sd, (struct sockaddr *)&clientAddr, sizeof(struct sockaddr_in)) == -1)
    {
        printf("CreateSocket failed (%d)\n", GetLastError());
        closesocket(sd);
        WSACleanup();
        exit(0);
    }
 
    while(1){
        printf("input anymessage: ");
        scanf("%s",tmp, BUFSIZ);
        strcpy(sendline,tmp);
        if(!strcmp(sendline, "q")) break;
        check=sendto(sd,sendline, strlen(sendline),0,(struct sockaddr*)&serverAddr,sizeof(serverAddr));
        if(check==-1)
            break;
        serversize=sizeof(serverAddr);
        n=recvfrom(sd,recvline,BUFSIZ,0,(struct sockaddr*)&serverAddr,&serversize);
        recvline[n]='\0';
        printf("receiveFormServer:");
        fputs(recvline,stdout);
        printf("\n");
         
         
    }
    closesocket(sd);
    return 0;
}

mutex를 걸어주는 방법에는 critical section (함수?) 도 있다고 한다.....

EVENT 생성시 마지막 인자로 들어가는 TEXT는 안주는 것이 좋다.

EVENT TEXT가 같으면 다른 프로그램에서도 같은 EVENT로 인식을 하기 때문에


-thread 종료를 시키는 방법


thread들은 while문을 돌때 조건으로 flag check를 한다.

delete(소멸자에서) 할때 flag set을 한뒤 waitEvent

thread에서 set된 flag를 확인하고 while문을 빠져나온다.

while문을 빠져나와 thread를 빠져 나오기전 setEvent를 해주면 이벤트를 기다리던 delete함수가 메모리 해제를 시작한다.



'Programming Language > C++' 카테고리의 다른 글

Why do we need virtual functions in c++?  (0) 2019.04.05
생성자 뒤에 콜론(:)  (0) 2017.03.08
MultiThread Programming  (0) 2016.08.17

+ Recent posts