c++下基于windows socket的多线程服务器(基于TCP协议)

  之前用c++实现过基于windows socket的单线程TCP服务器(http://www.cnblogs.com/jzincnblogs/p/5170230.html),今天实现了一个多线程的版本,可以接受多个客户端的请求,原理与之前的单线程版本相似,只是在多线程版本中主线程用于监测客户端请求,每当有新客户端请求连接,主线程便新开一个线程用户处理客户端的请求。代码如下:

  头文件:

 1 #ifndef SERVER_H
 2 #define SERVER_H
 3 
 4 #include <Winsock2.h>
 5 #include <windows.h>
 6 
 7 #pragma comment (lib, "ws2_32.lib")
 8 
 9 #define IP_BUF_SIZE 129
10 
11 class Server
12 {
13 public:
14     Server();
15     ~Server();
16     Server(const Server &) = delete;
17     Server & operator=(const Server &) = delete;
18     void WaitForClient();
19 private:
20     WORD winsock_ver;
21     WSADATA wsa_data;
22     SOCKET sock_svr;
23     SOCKET sock_clt;
24     HANDLE h_thread;
25     SOCKADDR_IN addr_svr;
26     SOCKADDR_IN addr_clt;
27     int ret_val;
28     int addr_len;
29     char buf_ip[IP_BUF_SIZE];
30 };
31 
32 #endif

  函数定义:

  1 #include "server.h"
  2 #include <iostream>
  3 #include <WS2tcpip.h>
  4 
  5 using std::cerr;
  6 using std::cout;
  7 using std::endl;
  8 
  9 #define SERVER_PORT 5000
 10 #define MSG_BUF_SIZE 1024
 11 
 12 Server::Server()
 13 {
 14     cout << "Initializing server...
";
 15     //
 16     winsock_ver = MAKEWORD(2, 2);
 17     addr_len = sizeof(SOCKADDR_IN);
 18     addr_svr.sin_family = AF_INET;
 19     addr_svr.sin_port = ::htons(SERVER_PORT);
 20     addr_svr.sin_addr.S_un.S_addr = ADDR_ANY;
 21     memset(buf_ip, 0, IP_BUF_SIZE);
 22     //
 23     ret_val = ::WSAStartup(winsock_ver, &wsa_data);
 24     if (ret_val != 0)
 25     {
 26         cerr << "WSA failed to start up!Error code: " << ::WSAGetLastError() << "
";
 27         system("pause");
 28         exit(1);
 29     }
 30     cout << "WSA started up successfully...
";
 31     //
 32     sock_svr = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 33     if (sock_svr == INVALID_SOCKET)
 34     {
 35         cerr << "Failed to create server socket!Error code: " << ::WSAGetLastError() << "
";
 36         ::WSACleanup();
 37         system("pause");
 38         exit(1);
 39     }
 40     cout << "Server socket created successfully...
";
 41     //
 42     ret_val = ::bind(sock_svr, (SOCKADDR*)&addr_svr, addr_len);
 43     if (ret_val != 0)
 44     {
 45         cerr << "Failed to bind server socket!Error code: " << ::WSAGetLastError() << "
";
 46         ::WSACleanup();
 47         system("pause");
 48         exit(1);
 49     }
 50     cout << "Server socket bound successfully...
";
 51     //
 52     ret_val = ::listen(sock_svr, SOMAXCONN);
 53     if (ret_val == SOCKET_ERROR)
 54     {
 55         cerr << "Server socket failed to listen!Error code: " << ::WSAGetLastError() << "
";
 56         ::WSACleanup();
 57         system("pause");
 58         exit(1);
 59     }
 60     cout << "Server socket started to listen...
";
 61     //
 62     cout << "Server started successfully..." << endl;
 63 }
 64 
 65 Server::~Server()
 66 {
 67     ::closesocket(sock_svr);
 68     ::closesocket(sock_clt);
 69     ::WSACleanup();
 70     cout << "Socket closed..." << endl;
 71 }
 72 
 73 DWORD WINAPI CreateClientThread(LPVOID lpParameter);
 74 //
 75 void Server::WaitForClient()
 76 {
 77     while (true)
 78     {
 79         sock_clt = ::accept(sock_svr, (SOCKADDR*)&addr_clt, &addr_len);
 80         if (sock_clt == INVALID_SOCKET)
 81         {
 82             cerr << "Failed to accept client!Error code: " << ::WSAGetLastError() << "
";
 83             ::WSACleanup();
 84             system("pause");
 85             exit(1);
 86         }
 87         ::InetNtop(addr_clt.sin_family, &addr_clt, buf_ip, IP_BUF_SIZE);
 88         cout << "A new client connected...IP address: " << buf_ip << ", port number: " << ::ntohs(addr_clt.sin_port) << endl;
 89         h_thread = ::CreateThread(nullptr, 0, CreateClientThread, (LPVOID)sock_clt, 0, nullptr);
 90         if (h_thread == NULL)
 91         {
 92             cerr << "Failed to create a new thread!Error code: " << ::WSAGetLastError() << "
";
 93             ::WSACleanup();
 94             system("pause");
 95             exit(1);
 96         }
 97         ::CloseHandle(h_thread);
 98     }
 99 }
100 
101 DWORD WINAPI CreateClientThread(LPVOID lpParameter)
102 {
103     SOCKET sock_clt = (SOCKET)lpParameter;
104     char buf_msg[MSG_BUF_SIZE];
105     int ret_val = 0;
106     int snd_result = 0;
107     do 
108     {
109         memset(buf_msg, 0, MSG_BUF_SIZE);
110         ret_val = ::recv(sock_clt, buf_msg, MSG_BUF_SIZE, 0);
111         if (ret_val > 0)
112         {
113             if (strcmp(buf_msg, "exit") == 0)
114             {
115                 cout << "Client requests to close the connection..." << endl;
116                 break;
117             }
118             cout << "Message received: " << buf_msg << endl;
119             snd_result = ::send(sock_clt, buf_msg, MSG_BUF_SIZE, 0);
120             if (snd_result == SOCKET_ERROR)
121             {
122                 cerr << "Failed to send message to client!Error code: " << ::GetLastError() << "
";
123                 ::closesocket(sock_clt);
124                 system("pause");
125                 return 1;
126             }
127         }
128         else if (ret_val == 0)
129         {
130             cout << "connection closed..." << endl;
131         }
132         else
133         {
134             cerr << "Failed to receive message from client!Error code: " << ::GetLastError() << "
";
135             ::closesocket(sock_clt);
136             system("pause");
137             return 1;
138         }
139     } while (ret_val > 0);
140     //
141     ret_val = ::shutdown(sock_clt, SD_SEND);
142     if (ret_val == SOCKET_ERROR)
143     {
144         cerr << "Failed to shutdown the client socket!Error code: " << ::GetLastError() << "
";
145         ::closesocket(sock_clt);
146         system("pause");
147         return 1;
148     }
149     return 0;
150 }

  程序入口:

1 #include "server.h"
2 
3 int main()
4 {
5     Server svr;
6     svr.WaitForClient();
7     system("pause");
8     return 0;
9 }
原文地址:https://www.cnblogs.com/jzincnblogs/p/5189636.html