文章标题 原创 翻译 转载 文章内容 需要注意的是要将listenSock设置为非阻塞模式,这样在while(1)循环中accept才不会被阻塞。同时listenSock也要set到fdread中,如果不这样做的话,select只能监视到客户端的socket,当客户端没有进行任务IO操作的时候select返回值为SOCKET_ERROR会一直进行循环检测,这样是没必要的。 如果有listenSock在fdread中,而又没有新的客户端接入的时候select会阻塞的,只要有一个客户端进行了IO操作或者有新客户端接入select就会变成非阻塞继续进行下面的处理。 在每次FD_SET之前必须FD_ZERO,所以这里使用了一个list来保存SOCKET,在下一次循环的时候重新FD_SET一遍list中的所有SOCKET。 ``` // TcpDemo.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> #include <Windows.h> #include <sstream> #include <list> #pragma comment(lib, "Ws2_32.lib") void handleConn(std::list<SOCKET> &clientSocks, fd_set &fdread); int _tmain(int argc, _TCHAR* argv[]) { WSADATA wsaData; SOCKET listenSock; SOCKADDR_IN serverAddr; SOCKADDR_IN clientAddr; fd_set fdread; int port = 5100; WSAStartup(MAKEWORD(2, 2), &wsaData); listenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == listenSock) { std::cout << "socket failed, errcode:" << WSAGetLastError() << std::endl; return 0; } unsigned long iMode = 1; ioctlsocket(listenSock, FIONBIO, &iMode); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(port); serverAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); int iret = bind(listenSock, (sockaddr*)&serverAddr, sizeof(serverAddr)); if (SOCKET_ERROR == iret) { std::cout << "bind failed, errcode:" << WSAGetLastError() << std::endl; closesocket(listenSock); return 0; } iret = listen(listenSock, SOMAXCONN); if ( SOCKET_ERROR == iret) { std::cout << "listen failed, errcode:" << WSAGetLastError() << std::endl; closesocket(listenSock); return 0; } int clientAddrLen = sizeof(clientAddr); std::list<SOCKET> clientSocks; while (1) { std::cout << "running" << std::endl; FD_ZERO(&fdread); FD_SET(listenSock, &fdread); SOCKET connSock = accept(listenSock, (sockaddr*)&clientAddr, &clientAddrLen); if (INVALID_SOCKET == connSock) { iret = WSAGetLastError(); if (WSAEWOULDBLOCK == iret) { std::cout << "waitting ..." << std::endl; } else { closesocket(listenSock); break; } } else { clientSocks.push_back(connSock); } std::list<SOCKET>::iterator iter = clientSocks.begin(); for ( ; iter!=clientSocks.end(); ++iter) { FD_SET(*iter, &fdread); } if (SOCKET_ERROR == select(0, &fdread, NULL, NULL, NULL)) { std::cout << "select failed, errcode:" << WSAGetLastError() << std::endl; continue; } handleConn(clientSocks, fdread); } system("pause"); return 0; } void handleConn(std::list<SOCKET> &clientSocks, fd_set &fdread) { std::cout << "handle connection" << std::endl; std::list<SOCKET>::iterator iter = clientSocks.begin(); while (iter != clientSocks.end()) { bool isError = false; if (FD_ISSET(*iter, &fdread)) { char buf[1000]; int irecv = recv(*iter, buf, sizeof(buf), 0); int lastError = 0; if (SOCKET_ERROR == irecv || 0 == irecv) { lastError = WSAGetLastError(); std::cout << "socket:" << *iter << ", erase, lasterror:" << lastError << std::endl; isError = true; } else { int isend = send(*iter, buf, irecv, 0); if (isend < 0) { lastError = WSAGetLastError(); if (WSAEWOULDBLOCK == lastError) { ::Sleep(100); } else { isError = true; std::cout << "echo error, lasterror:" << lastError << std::endl; } } } } if (isError) { closesocket(*iter); clientSocks.erase(iter++); } else { ++iter; } } } ``` 文章类别 Python Mobile Android Java Shell Life Database Bug Windows IOS Tools Boost Node.js Mac Product Tips C/C++ Golang Javascript React Qt MQ MongoDB Design Web Linux LLM ChatGPT RAG AI 提交