c++下基于windows socket的单线程服务器客户端程序
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++下基于windows socket的单线程服务器客户端程序相关的知识,希望对你有一定的参考价值。
今天自己用编写了一个简单的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 14 //服务器 15 int main() { 16 WSADATA wsa_data; //WSADATA变量,包含windows socket执行的信息 17 int i_result = 0; //接收返回值 18 SOCKET sock_server = INVALID_SOCKET; //创建服务器套接字 19 SOCKET sock_client = INVALID_SOCKET; //创建客户端套接字 20 //addrinfo是getaddrinfo()函数用来保存主机地址信息的结构体 21 addrinfo *result = nullptr; //result是存储地址信息的链表 22 addrinfo hints; 23 //初始化winsock动态库(ws2_32.dll),MAKEWORD(2, 2)用于请求使用winsock2.2版本 24 i_result = WSAStartup(MAKEWORD(2, 2), &wsa_data); 25 if (i_result != 0) { 26 cerr << "WSAStartup() function failed: " << i_result << "\n"; 27 system("pause"); 28 return 1; 29 } 30 //用0填充内存区域,是ZeroMemory的更安全版本 31 SecureZeroMemory(&hints, sizeof(addrinfo)); 32 hints.ai_family = AF_INET; 33 hints.ai_socktype = SOCK_STREAM; //流式套接字用于TCP协议 34 hints.ai_protocol = IPPROTO_TCP; 35 hints.ai_flags = AI_PASSIVE; //socket的地址会被用于bind()函数的调用 36 //确定服务器的地址与端口,将相关信息写入result中 37 i_result = getaddrinfo(nullptr, DEFAULT_PORT, &hints, &result); 38 if (i_result != 0) { 39 cerr << "getaddrinfo() function failed with error: " << WSAGetLastError() << "\n"; 40 WSACleanup(); 41 system("pause"); 42 return 1; 43 } 44 //创建服务器套接字 45 sock_server = socket(result->ai_family, result->ai_socktype, result->ai_protocol); 46 //套接字创建失败 47 if (sock_server == INVALID_SOCKET) { 48 cerr << "socket() function failed with error: " << WSAGetLastError() << "\n"; 49 //将getaddrinfo()函数动态分配的addrinfo中的地址信息释放掉 50 freeaddrinfo(result); 51 //释放套接字资源 52 WSACleanup(); 53 system("pause"); 54 return 1; 55 } 56 //将服务器套接字与地址对象绑定,result->ai_addr是结构体的指针 57 i_result = bind(sock_server, result->ai_addr, static_cast<int>(result->ai_addrlen)); 58 //绑定失败 59 if (i_result == SOCKET_ERROR) { 60 cerr << "bind() function failed with error: " << WSAGetLastError() << "\n"; 61 freeaddrinfo(result); 62 closesocket(sock_server); 63 WSACleanup(); 64 system("pause"); 65 return 1; 66 } 67 freeaddrinfo(result); 68 cout << "server started successfully..." << endl; 69 //开始监听 70 cout << "start listening..." << endl; 71 i_result = listen(sock_server, SOMAXCONN); 72 if (i_result == SOCKET_ERROR) { 73 cerr << "listen() function failed with error: " << WSAGetLastError() << "\n"; 74 closesocket(sock_server); 75 system("pause"); 76 return 1; 77 } 78 //接收客户端请求 79 sock_client = accept(sock_server, nullptr, nullptr); 80 if (sock_client == INVALID_SOCKET) { 81 cerr << "accept() function failed with error: " << WSAGetLastError() << "\n"; 82 closesocket(sock_server); 83 WSACleanup(); 84 system("pause"); 85 return 1; 86 } 87 //接收和发送数据 88 char recv_buf[RECV_BUF_SIZE]; 89 int send_result = 0; 90 do { 91 //不可缺少,若不将内存空间清零会输出乱码,这是因为输送过来的信息未必有256个字节 92 SecureZeroMemory(recv_buf, RECV_BUF_SIZE); 93 //标志位一般设置为0 94 i_result = recv(sock_client, recv_buf, RECV_BUF_SIZE, 0); 95 if (i_result > 0) { 96 //exit表示客户端请求断开连接 97 if (strcmp(recv_buf, "exit") == 0) { 98 cout << "client request to close the connection..." << endl; 99 break; 100 } 101 //输出接收的字节数 102 cout << "Bytes received: " << i_result << endl; 103 cout << "message received: " << recv_buf << endl; 104 //向客户端发送接收到的数据 105 send_result = send(sock_client, recv_buf, i_result, 0); 106 if (send_result == SOCKET_ERROR) { 107 cerr << "send() function failed with error: " << WSAGetLastError() << "\n"; 108 closesocket(sock_client); 109 WSACleanup(); 110 system("pause"); 111 return 1; 112 } 113 cout << "Bytes sent: " << send_result << endl; 114 } 115 //i_result的值为0表示连接已经关闭 116 else if (i_result == 0) { 117 cout << "connection closed..." << endl; 118 } 119 else { 120 cerr << "recv() function failed with error: " << WSAGetLastError() << "\n"; 121 closesocket(sock_client); 122 WSACleanup(); 123 system("pause"); 124 return 1; 125 } 126 } while (i_result > 0); //do...while语句后注意要有分号 127 //shutdown()禁用套接字的接收或发送功能 128 i_result = shutdown(sock_client, SD_SEND); 129 if (i_result == SOCKET_ERROR) { 130 cerr << "shutdown() function failed with error: " << WSAGetLastError() << "\n"; 131 closesocket(sock_client); 132 WSACleanup(); 133 system("pause"); 134 return 1; 135 } 136 //关闭套接字 137 i_result = closesocket(sock_server); 138 WSACleanup(); 139 cout << "socket closed..." << endl; 140 system("pause"); 141 return 0; 142 }
客户端:
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 << "\n"; 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() << "\n"; 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() << "\n"; 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() << "\n"; 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 >> send_buf; 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() << "\n"; 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() << "\n"; 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() << "\n"; 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 }
以上是关于c++下基于windows socket的单线程服务器客户端程序的主要内容,如果未能解决你的问题,请参考以下文章