C++ Windows 上简单的非阻塞Select模型
说明:当客户端连接数超过64个的时候,每次最多select64个,但每一帧可以select多次,理论上可以突破fd个数的限制
.h
#ifndef _MODULE_SELECT_H_ #define _MODULE_SELECT_H_ #include "platform/platform.h" class CModuleSelect { public: CModuleSelect(); ~CModuleSelect(); public: int32_t Initialize(); int32_t Uninitialize(); void ProcessEvent(uint32_t nTimeUsec); public: int32_t AddFd(int32_t fd); int32_t DelFd(uint32_t index); protected: void FDSet(int32_t fd) { FD_SET(fd, &readfds); FD_SET(fd, &writefds); FD_SET(fd, &errorfds); if (fd + 1 > maxfdp){ maxfdp = fd + 1; } } void FDZero() { FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&errorfds); maxfdp = 0; } void FDClear(int32_t fd) { FD_CLR(fd, &readfds); FD_CLR(fd, &writefds); FD_CLR(fd, &errorfds); }; private: int32_t sListen; // fd_set for select int32_t maxfdp; struct fd_set readfds, writefds, errorfds; // all used fd uint32_t unFdSize; int32_t *arrFd; }; #endif
.cpp
#include "module_select.h" #include "common/common.h" CModuleSelect::CModuleSelect() { unFdSize = 0; arrFd = new int32_t[unMaxFdSize]; } CModuleSelect::~CModuleSelect() { Uninitialize(); } int32_t CModuleSelect::Initialize() { WSADATA wsaData; int32_t nRet = WSAStartup(0x0202, &wsaData); if (nRet != S_OK){ return WSAGetLastError(); } sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); nRet = AddFd(sListen); if (nRet != S_OK){ return nRet; } SOCKADDR_IN addrLocal; addrLocal.sin_addr.S_un.S_addr = htonl(INADDR_ANY); addrLocal.sin_family = AF_INET; addrLocal.sin_port = htons(nPort); // bind nRet = bind(sListen, (struct sockaddr*)&addrLocal, sizeof(SOCKADDR_IN)); if (nRet != S_OK){ return WSAGetLastError(); } // listen nRet = listen(sListen, 5); if (nRet != S_OK){ return WSAGetLastError(); } printf("listen:%d\n", sListen); return S_OK; } void CModuleSelect::ProcessEvent(uint32_t nTimeUsec) { int32_t nRet = S_OK; static struct timeval timeout; timeout.tv_sec = nTimeUsec / 1000000; timeout.tv_usec = nTimeUsec % 1000000; static int32_t addrSize = sizeof(SOCKADDR_IN); static char buf[1024]; static SOCKADDR_IN addrRemote; // select all used fd uint32_t unStartPos = 0, unEndPos = 0; do { // reset fd_set FDZero(); // fd_set size limited by 'FD_SETSIZE' for (uint32_t i = 0; i < FD_SETSIZE && unEndPos < unFdSize; ++i) { FDSet(arrFd[unEndPos++]); } nRet = select(maxfdp, &readfds, &writefds, &errorfds, &timeout); // select error if (nRet == -1) { int32_t nError = WSAGetLastError(); perrors("select error,nRet=%d,info=%s\n", nError, strerror(nError)); exit(1); } // time out ,nothing happened else if (nRet == 0) { printf("."); continue; } // some thing happened else if (nRet > 0) { // check events for (uint32_t i = unStartPos; i < unEndPos; ++i) { // read events if ( FD_ISSET(arrFd[i],&readfds) ) { printf("[%d]:read = %d\n",i,arrFd[i]); if (sListen == arrFd[i]) { nRet = accept(sListen, (struct sockaddr*)&addrRemote, &addrSize); printf("Accepted client:%s:%d\n", inet_ntoa(addrRemote.sin_addr), ntohs(addrRemote.sin_port)); AddFd(nRet); } else { nRet = recv(arrFd[i], buf, 1024, 0); if (nRet == 0 || nRet == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET) { // client close DelFd(i); } else { // received correct data from client buf[nRet] = '\0'; send(arrFd[i], buf, strlen(buf), 0); } } } // write events else if (FD_ISSET(arrFd[i], &writefds)) { Sleep(1); //printf("write = %d\n", arrFd[i]); } // error events else if (FD_ISSET(arrFd[i], &errorfds)) { printf("error = %d\n", arrFd[i]); } } } // for next loop unStartPos = unEndPos; }while (unEndPos < unFdSize); } int32_t CModuleSelect::Uninitialize() { return WSACleanup(); } int32_t CModuleSelect::AddFd(int32_t fd) { if (unFdSize < unMaxFdSize) { arrFd[unFdSize++] = fd; return S_OK; } return -1; } int32_t CModuleSelect::DelFd(uint32_t index) { if (unFdSize > 1 && index > 0 && unFdSize > index) { closesocket(arrFd[index]); arrFd[index] = arrFd[unFdSize - 1]; --unFdSize; } return S_OK; }