今天自己编写了一个简单的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 }