c++下基于windows socket的单线程服务器客户端程序(基于TCP协议)

今天自己编写了一个简单的c++服务器客户端程序,注释较详细,在此做个笔记。

windows下socket编程的主要流程可概括如下:初始化ws2_32.dll动态库-->创建套接字-->绑定地址信息-->服务器进行监听/客户端连接服务器-->数据交换-->关闭套接字对象。

服务器端:

  1 #include <Winsock2.h>
  2 #include <Ws2tcpip.h>
  3 #include <iostream>
  4 
  5 #pragma comment(lib, "ws2_32.lib") //socket编程需要引用该库
  6 
  7 using std::cerr;
  8 using std::cout;
  9 using std::endl;
 10 
 11 const char DEFAULT_PORT[] = "4000";
 12 const int RECV_BUF_SIZE = 256;
 13 const size_t IP_BUF_SIZE = 65;
 14 
 15 //服务器
 16 int main() {
 17     WSADATA wsa_data; //WSADATA变量,包含windows socket执行的信息
 18     int i_result = 0; //接收返回值
 19     SOCKET sock_server = INVALID_SOCKET; //创建服务器套接字
 20     SOCKET sock_client = INVALID_SOCKET; //创建客户端套接字
 21     //addrinfo是getaddrinfo()函数用来保存主机地址信息的结构体
 22     addrinfo *result = nullptr; //result是存储地址信息的链表
 23     addrinfo hints;
 24     //初始化winsock动态库(ws2_32.dll),MAKEWORD(2, 2)用于请求使用winsock2.2版本
 25     i_result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
 26     if (i_result != 0) {
 27         cerr << "WSAStartup() function failed: " << i_result << "
";
 28         system("pause");
 29         return 1;
 30     }
 31     //用0填充内存区域,是ZeroMemory的更安全版本
 32     SecureZeroMemory(&hints, sizeof(addrinfo));
 33     hints.ai_family = AF_INET;
 34     hints.ai_socktype = SOCK_STREAM; //流式套接字用于TCP协议
 35     hints.ai_protocol = IPPROTO_TCP;
 36     hints.ai_flags = AI_PASSIVE; //socket的地址会被用于bind()函数的调用
 37     //确定服务器的地址与端口,将相关信息写入result中
 38     i_result = getaddrinfo(nullptr, DEFAULT_PORT, &hints, &result);
 39     if (i_result != 0) {
 40         cerr << "getaddrinfo() function failed with error: " << WSAGetLastError() << "
";
 41         WSACleanup();
 42         system("pause");
 43         return 1;
 44     }
 45     //创建服务器套接字
 46     sock_server = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
 47     //套接字创建失败
 48     if (sock_server == INVALID_SOCKET) {
 49         cerr << "socket() function failed with error: " << WSAGetLastError() << "
";
 50         //将getaddrinfo()函数动态分配的addrinfo中的地址信息释放掉
 51         freeaddrinfo(result);
 52         //释放套接字资源
 53         WSACleanup();
 54         system("pause");
 55         return 1;
 56     }
 57     //将服务器套接字与地址对象绑定,result->ai_addr是结构体的指针
 58     i_result = bind(sock_server, result->ai_addr, static_cast<int>(result->ai_addrlen));
 59     //绑定失败
 60     if (i_result == SOCKET_ERROR) {
 61         cerr << "bind() function failed with error: " << WSAGetLastError() << "
";
 62         freeaddrinfo(result);
 63         closesocket(sock_server);
 64         WSACleanup();
 65         system("pause");
 66         return 1;
 67     }
 68     freeaddrinfo(result);
 69     cout << "server started successfully..." << endl;
 70     //开始监听
 71     cout << "start listening..." << endl;
 72     i_result = listen(sock_server, SOMAXCONN);
 73     if (i_result == SOCKET_ERROR) {
 74         cerr << "listen() function failed with error: " << WSAGetLastError() << "
";
 75         closesocket(sock_server);
 76         system("pause");
 77         return 1;
 78     }
 79     //接收客户端请求,获取客户端ip地址
 80     SOCKADDR_IN addr_client;
 81     int len_addr = sizeof(SOCKADDR_IN);
 82     char ip_buf[IP_BUF_SIZE];
 83     SecureZeroMemory(ip_buf, IP_BUF_SIZE);
 84     sock_client = accept(sock_server, (SOCKADDR*)&addr_client, &len_addr);
 85     if (sock_client == INVALID_SOCKET) {
 86         cerr << "accept() function failed with error: " << WSAGetLastError() << "
";
 87         closesocket(sock_server);
 88         WSACleanup();
 89         system("pause");
 90         return 1;
 91     }
 92     cout << "client connected..." << endl;
 93     //ip地址转换
 94     inet_ntop(AF_INET, &addr_client, ip_buf, IP_BUF_SIZE);
 95     cout << "client ip address: " << ip_buf << endl;
 96     //接收和发送数据
 97     char recv_buf[RECV_BUF_SIZE];
 98     int send_result = 0;
 99     do {
100         //不可缺少,若不将内存空间清零会输出乱码,这是因为输送过来的信息未必有256个字节
101         SecureZeroMemory(recv_buf, RECV_BUF_SIZE);
102         //标志位一般设置为0
103         i_result = recv(sock_client, recv_buf, RECV_BUF_SIZE, 0);
104         if (i_result > 0) {
105             //exit表示客户端请求断开连接
106             if (strcmp(recv_buf, "exit") == 0) {
107                 cout << "client requests to close the connection..." << endl;
108                 break;
109             }
110             //输出接收的字节数
111             cout << "Bytes received: " << i_result << endl;
112             cout << "message received: " << recv_buf << endl;
113             //向客户端发送接收到的数据
114             send_result = send(sock_client, recv_buf, i_result, 0);
115             if (send_result == SOCKET_ERROR) {
116                 cerr << "send() function failed with error: " << WSAGetLastError() << "
";
117                 closesocket(sock_client);
118                 WSACleanup();
119                 system("pause");
120                 return 1;
121             }
122         }
123         //i_result的值为0表示连接已经关闭
124         else if (i_result == 0) {
125             cout << "connection closed..." << endl;
126         }
127         else {
128             cerr << "recv() function failed with error: " << WSAGetLastError() << "
";
129             closesocket(sock_client);
130             WSACleanup();
131             system("pause");
132             return 1;
133         }
134     } while (i_result > 0); //do...while语句后注意要有分号
135     //shutdown()禁用套接字的接收或发送功能
136     i_result = shutdown(sock_client, SD_SEND);
137     if (i_result == SOCKET_ERROR) {
138         cerr << "shutdown() function failed with error: " << WSAGetLastError() << "
";
139         closesocket(sock_client);
140         WSACleanup();
141         system("pause");
142         return 1;
143     }
144     //关闭套接字
145     i_result = closesocket(sock_server);
146     WSACleanup();
147     cout << "socket closed..." << endl;
148     system("pause");
149     return 0;
150 }

客户端:

  1 #include <iostream>
  2 #include <WinSock2.h>
  3 #include <Ws2tcpip.h>
  4 
  5 #pragma comment(lib, "ws2_32.lib")
  6 
  7 using std::cin;
  8 using std::cerr;
  9 using std::cout;
 10 using std::endl;
 11 using std::flush;
 12 
 13 const char DEFAULT_PORT[] = "4000";
 14 const int SEND_BUF_SIZE = 256;
 15 
 16 //客户端
 17 int main() {
 18     WSADATA wsa_data; //WSADATA变量,包含windows socket执行的信息
 19     int i_result = 0; //接收返回值
 20     SOCKET sock_client = INVALID_SOCKET;
 21     addrinfo *result = nullptr, hints;
 22     //初始化winsock动态库(ws2_32.dll),MAKEWORD(2, 2)用于请求使用winsock2.2版本
 23     i_result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
 24     if (i_result != 0) {
 25         cerr << "WSAStartup() function failed: " << i_result << "
";
 26         system("pause");
 27         return 1;
 28     }
 29     SecureZeroMemory(&hints, sizeof(hints));
 30     hints.ai_family = AF_UNSPEC;
 31     hints.ai_socktype = SOCK_STREAM;
 32     hints.ai_protocol = IPPROTO_TCP;
 33     //
 34     i_result = getaddrinfo("127.0.0.1", DEFAULT_PORT, &hints, &result);
 35     if (i_result != 0) {
 36         cerr << "getaddrinfo() function failed with error: " << WSAGetLastError() << "
";
 37         WSACleanup();
 38         system("pause");
 39         return 1;
 40     }
 41     //创建套接字
 42     sock_client = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
 43     if (sock_client == INVALID_SOCKET) {
 44         cerr << "socket() function failed with error: " << WSAGetLastError() << "
";
 45         WSACleanup();
 46         system("pause");
 47         return 1;
 48     }
 49     //连接服务器
 50     i_result = connect(sock_client, result->ai_addr, result->ai_addrlen);
 51     if (i_result == SOCKET_ERROR) {
 52         cerr << "connect() function failed with error: " << WSAGetLastError() << "
";
 53         WSACleanup();
 54         system("pause");
 55         return 1;
 56     }
 57     cout << "connect server successfully..." << endl;
 58     //
 59     freeaddrinfo(result);
 60     //
 61     char send_buf[SEND_BUF_SIZE];
 62     int recv_result = 0;
 63     //SecureZeroMemory(send_buf, SEND_BUF_SIZE);
 64     do {
 65         cout << "enter the message that you want to send: " << flush;
 66         cin.getline(send_buf, SEND_BUF_SIZE);
 67         i_result = send(sock_client, send_buf, static_cast<int>(strlen(send_buf)), 0);
 68         if (i_result == SOCKET_ERROR) {
 69             cerr << "send() function failed with error: " << WSAGetLastError() << "
";
 70             closesocket(sock_client);
 71             WSACleanup();
 72             system("pause");
 73             return 1;
 74         }
 75         cout << "Bytes sent: " << i_result << endl;
 76         //接收服务器返回的数据
 77         recv_result = recv(sock_client, send_buf, SEND_BUF_SIZE, 0);
 78         if (recv_result > 0) {
 79             cout << "feedback from server: " << send_buf << endl;
 80         }
 81         else if (recv_result == 0) {
 82             cout << "connection closed..." << endl;
 83         }
 84         else {
 85             cerr << "recv() function failed with error: " << WSAGetLastError() << "
";
 86             closesocket(sock_client);
 87             WSACleanup();
 88             system("pause");
 89             return 1;
 90         }
 91     } while (recv_result > 0);
 92     //
 93     i_result = shutdown(sock_client, SD_SEND);
 94     if (i_result == SOCKET_ERROR) {
 95         cerr << "shutdown() function failed with error: " << WSAGetLastError() << "
";
 96         closesocket(sock_client);
 97         WSACleanup();
 98         system("pause");
 99         return 1;
100     }
101     closesocket(sock_client);
102     WSACleanup();
103     cout << "socket closed..." << endl;
104     system("pause");
105     return 0;
106 }
原文地址:https://www.cnblogs.com/jzincnblogs/p/5170230.html