
在 Socket 编程中,发送数据的函数 send() 和接收数据的函数 recv() ,往往需要等待发送和接收完成返回相应的值后才能执行下一条指令。所以当我们把 send() 和 recv() 放到同一个函数流程里的时候往往会导致I/O阻塞,无法实现同时收发数据。使用多线程编程,将监听函数、接收函数和发送函数分别放入不同的线程中,可以很好的避免出现以上问题。
如下为 Windows 下使用 Socket 编写 C/S 架构多线程通信 Demo ,代码很简单。
流程图
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 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 152 153 154 155 156 157 158 |
#include <iostream> #include <WinSock2.h> #include <process.h> #include <Windows.h> #pragma comment(lib, "ws2_32.lib") using namespace std; SOCKET serverSocket, clientSocket; struct sockaddr_in addrSrv; struct sockaddr_in addrCli; char IP[20]; /*初始化Socket*/ int InitSocket(){ WSADATA wsaData; //加载Socket库 int err; err = WSAStartup(MAKEWORD(2, 2), &wsaData); if (err != 0) { cout << "加载Socket库失败" << endl; return 0; } //IP地址 //默认的网卡:= htonl(INADDR_ANY); //固定IP:= inet_addr("127.0.0.1"); addrSrv.sin_addr.s_addr = htonl(INADDR_ANY); //协议 addrSrv.sin_family = AF_INET; //端口 addrSrv.sin_port = htons(4000); //创建服务端Socket serverSocket = socket(AF_INET, SOCK_STREAM, 0); if (serverSocket == INVALID_SOCKET) { cout << "创建Socket失败!" << endl; return 0; } //绑定端口和IP地址 err = bind(serverSocket, (sockaddr*)&addrSrv, sizeof(sockaddr)); if (err == SOCKET_ERROR) { closesocket(serverSocket); cout << "绑定失败" << endl; return 0; } } /*关闭Socket并释放占用资源*/ void CleanFun() { closesocket(serverSocket); closesocket(clientSocket); WSACleanup(); } /*监听线程*/ UINT __stdcall ListenThread(LPVOID lParam) { while (1) { //开启监听,最大连接数5 int erro = listen(serverSocket, 5); if (erro == SOCKET_ERROR) { return 1; } //accept客户端连接 int len = sizeof(addrCli); clientSocket = accept(serverSocket, (sockaddr*)&addrCli, &len); if (clientSocket == INVALID_SOCKET) { return 1; } //输出客户端IP char * IPaddr = inet_ntoa(addrCli.sin_addr); memcpy(IP, IPaddr, strlen(IPaddr)); cout << "客户端 " << IP << " 连接!" << endl; Sleep(100); } return 1; } /*发送线程*/ UINT __stdcall SendThread(LPVOID lParam) { char sendBuf[65535]; //清理缓存区 ZeroMemory(sendBuf, sizeof(sendBuf)); while (1) { //将发送的数据写入缓冲区 cin.getline(sendBuf, 65535); //发送缓冲区数据到客户端 if (send(clientSocket, sendBuf, sizeof(sendBuf), 0) == SOCKET_ERROR) { cout << "发送失败!"; return 0; } } return 1; } /*接收线程*/ UINT __stdcall RecvThread(LPVOID lParam) { while (1) { char recvBuf[65535]; //清理缓存区 ZeroMemory(recvBuf, sizeof(recvBuf)); //接收数据并写入缓冲区 int ret; ret = recv(clientSocket, recvBuf, sizeof(recvBuf), 0); //接收失败 if (ret == 0) { cout << "接收失败!" << endl; return 0; } //接收成功,输出数据 if (ret > 0) { cout << IP << ":" << recvBuf << endl; } Sleep(100); } return 1; } int main(void) { //IP初始化 ZeroMemory(IP, sizeof(IP)); //初始化Socket InitSocket(); cout << "服务端已启动。" << endl; //启动线程 _beginthreadex(NULL, NULL, ListenThread, NULL, NULL, NULL); cout << "监听线程已启动。" << endl; _beginthreadex(NULL, NULL, RecvThread, NULL, NULL, NULL); cout << "接收线程已启动。" << endl; _beginthreadex(NULL, NULL, SendThread, NULL, NULL, NULL); cout << "发送线程已启动。" << endl; //循环 while (1) { Sleep(100);//让线程有时间运行,避免空循环 } //清理 CleanFun(); return 1; } |
CLIENT
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 |
#include<iostream> #include<WinSock2.h> #include <process.h> #include <string> #include <Windows.h> #pragma comment(lib, "ws2_32.lib") using namespace std; SOCKET clientSocket; sockaddr_in addrClient; /*初始化Socket*/ int InitSocket() { WSADATA wsaData; //加载Socket库 int err; err = WSAStartup(MAKEWORD(2, 2), &wsaData); if (err != 0) { cout << "加载Socket库失败" << endl; return 0; } //IP地址绑定 addrClient.sin_addr.s_addr = inet_addr("127.0.0.1"); //协议 addrClient.sin_family = AF_INET; //端口 addrClient.sin_port = htons(4000); //创建客户端Socket clientSocket = socket(AF_INET, SOCK_STREAM, 0); if (clientSocket == INVALID_SOCKET) { cout << "创建Socket失败!" << endl; return 0; } //客户端不需要绑定 //连接服务端 if (connect(clientSocket, (sockaddr*)&addrClient, sizeof(addrClient)) == SOCKET_ERROR) { cout << "连接服务端失败!"; return 1; } return 1; } /*关闭Socket并释放占用资源*/ void CleanFun() { closesocket(clientSocket); WSACleanup(); } /*发送线程*/ UINT __stdcall SendThread(LPVOID lParam) { char sendBuf[65535]; //清理缓存区 ZeroMemory(sendBuf, sizeof(sendBuf)); while (1) { //将发送的数据写入缓冲区 cin.getline(sendBuf, 65535); //发送缓冲区数据到客户端 if (send(clientSocket, sendBuf, sizeof(sendBuf), 0) == SOCKET_ERROR) { cout << "发送失败!"; return 0; } Sleep(50); } return 1; } /*接收线程*/ UINT __stdcall RecvThread(LPVOID lParam) { while (1) { char recvBuf[65535]; //清理缓存区 ZeroMemory(recvBuf, sizeof(recvBuf)); //接收数据并写入缓冲区 int ret; ret = recv(clientSocket, recvBuf, sizeof(recvBuf), 0); //接收失败 if (ret == 0) { cout << "接收失败!" << endl; return 0; } //接收成功,输出数据 if (ret > 0) { cout << "Server:" << recvBuf << endl; } Sleep(50); } return 1; } int main(void) { //初始化Socket InitSocket(); //启动线程 _beginthreadex(NULL, NULL, SendThread, NULL, NULL, NULL); _beginthreadex(NULL, NULL, RecvThread, NULL, NULL, NULL); //循环 while (1) { Sleep(500); } //清理 CleanFun(); } |
如无注明,均为原创。转载请注明: 转载自MITGAI`S THINKING
本文链接地址: Windows Socket C/S 多线程通信程序
本文链接地址: Windows Socket C/S 多线程通信程序
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
如果本文对您生活或工作产生了积极影响,那我非常高兴。
如果您愿意为文章的内容或想法提供支持,欢迎点击下边的捐赠按钮,资助作者创作更多高价值高品质的内容。
如果您愿意为文章的内容或想法提供支持,欢迎点击下边的捐赠按钮,资助作者创作更多高价值高品质的内容。