通过select模型,可以在多个客户端连接的情况下,无需创建多个线程处理即单线程处理。 以下示例: Client端向Server端发送数据,Server端接收数据并输出。
Server.cpp
#include <iostream> #include <windows.h> using namespace std; #pragma comment(lib, "Ws2_32.lib") #define PORT_NO 6000 #define BACKLOG 10 int main(int argc, char* argv[]) { WSADATA wsaData; int ret; WORD wVersionRequested = MAKEWORD(2, 2); SOCKET sockSrv; SOCKADDR_IN addrSrv, addrClient; HANDLE hThread = NULL; // 初始化Windows Socket------ ret = WSAStartup(wVersionRequested, &wsaData); if (ret != 0) { cout << "WSAStartup() failed:" << WSAGetLastError() << endl; return -1; } // 创建Socket------ sockSrv = socket(AF_INET, SOCK_STREAM, 0); if (INVALID_SOCKET == sockSrv) { cout << "socket() failed:" << WSAGetLastError() << endl; WSACleanup(); return -1; } addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(PORT_NO); // Bind Socket------ ret = bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); if (SOCKET_ERROR == ret) { cout << "bind() failed:" << WSAGetLastError() << endl; closesocket(sockSrv); WSACleanup(); return -1; } // 监听------ ret = listen(sockSrv, BACKLOG); if (SOCKET_ERROR == ret) { cout << "listen() failed:" << WSAGetLastError() << endl; closesocket(sockSrv); WSACleanup(); return -1; } cout<< "Server started......" << endl; // select------ //单线程实现多客户端处理 fd_set fdSocketAll; // 记录所有socket FD_ZERO(&fdSocketAll); FD_SET(sockSrv, &fdSocketAll); while (1) { fd_set fdRead = fdSocketAll; ret = select(0, &fdRead, NULL, NULL, NULL); if (0 == ret) // 超时,由于timeout设为NULL,所有没有超时之说 { cout << "over time..." << endl; continue; } else if (ret > 0) // ok { #pragma region for (int i=0; i<(int)fdRead.fd_count; ++i) { SOCKET sock = fdRead.fd_array[i]; if (sock == sockSrv) // 监听套接字接受到新连接 { int len=sizeof(SOCKADDR); SOCKET sockConn = accept(sockSrv, (SOCKADDR*)&addrClient, &len); if (INVALID_SOCKET == sockConn) { cout << "accept() failed:" << WSAGetLastError() << endl; break; } cout << "接受到新连接:" << ::inet_ntoa(addrClient.sin_addr) << endl; if (fdSocketAll.fd_count < FD_SETSIZE) { FD_SET(sockConn, &fdSocketAll); } else { cout << "Too much connections!" << endl; closesocket(sockConn); } } else // 有数据可读取 { char recvBuffer[MAX_PATH] = {0}; ret = recv(sock, recvBuffer, sizeof(recvBuffer), 0); if (ret == 0) { cout << "Connection has been gracefully closed." << endl; FD_CLR(sock, &fdSocketAll); closesocket(sock); continue; } else if (ret == SOCKET_ERROR) { cout << "Connection has been closed ungracefully." << endl; FD_CLR(sock, &fdSocketAll); closesocket(sock); continue; } cout << "Receive Data from Client:" << recvBuffer << endl; } } #pragma endregion } else // error { cout << "select() failed:" << WSAGetLastError() << endl; break; } } // 清理资源------ for (int i=0; i<(int)fdSocketAll.fd_count; ++i) { closesocket(fdSocketAll.fd_array[i]); } WSACleanup(); cout << "exit..." << endl; return 0; }
Client.cpp
#include <iostream> #include <windows.h> using namespace std; #pragma comment(lib, "Ws2_32.lib") #define PORT_NO 6000 #define SRV_IP_ADDR "127.0.0.1" int main(int argc, char* argv[]) { int ret; WSADATA wsaData; WORD wVersionRequested = MAKEWORD(2, 2); SOCKET sockClient; SOCKADDR_IN addrSrv; // 初始化Windows Socket------ ret = WSAStartup(wVersionRequested, &wsaData); if (ret != 0) { cout << "WSAStartup() failed:" << WSAGetLastError() << endl; return -1; } // 创建Socket------ sockClient = socket(AF_INET, SOCK_STREAM, 0); if (INVALID_SOCKET == sockClient) { cout << "socket() failed:" << WSAGetLastError() << endl; WSACleanup(); return -1; } addrSrv.sin_addr.S_un.S_addr = inet_addr(SRV_IP_ADDR); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(PORT_NO); // 连接------ ret = connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); if (SOCKET_ERROR == ret) { cout << "connect() failed:" << WSAGetLastError() << endl; closesocket(sockClient); WSACleanup(); return -1; } else { cout << "connect() successfully." << endl; } // 发送数据------ char sendBuf[MAX_PATH] = {0}; while (1) { cin.getline(sendBuf, sizeof(sendBuf)); if (strcmp(sendBuf, "exit") == 0) { break; } ret = send(sockClient, sendBuf, strlen(sendBuf)+1, 0); if (SOCKET_ERROR == ret) { cout << "send() failed:" << WSAGetLastError() << endl; closesocket(sockClient); WSACleanup(); return -1; } } // 清理资源------- closesocket(sockClient); WSACleanup(); cout << "exit..." << endl; return 0; }