select io 多路复用

来源:互联网 发布:linux极点五笔输入法 编辑:程序博客网 时间:2024/05/16 23:43


select主要用于检测多个fd状态,可检测fd大小收内核编译宏__FD_SETSIZE限制,默认为1024。

当打开的fd较多时,select的效率会降低。可修改下面简单服务器模型为仅接受连接,当fd数量超过20000时,select返回明显变慢。


1.简单单线程同时处理多连接的服务器模型

void testSelectSocket(){int nListenFd; int nLen; struct sockaddr_in ServerAddress,ClientAddress; int result; fd_set readfds, testfds; nListenFd = socket(AF_INET, SOCK_STREAM, 0);ServerAddress.sin_family = AF_INET; ServerAddress.sin_addr.s_addr = htonl(INADDR_ANY); ServerAddress.sin_port = htons(1234); nLen = sizeof(ServerAddress); bind(nListenFd, (struct sockaddr *)&ServerAddress, nLen); listen(nListenFd, 5);printf("listen %d\r\n",nListenFd);fd_set readFds;std::set<int> ClientFds;while(1){FD_ZERO(&readFds);FD_SET(nListenFd,&readFds);std::set<int>::const_iterator it(ClientFds.begin()),itEnd(ClientFds.end());for(;it != itEnd;++it)FD_SET(*it,&readFds);int nRet = select(FD_SETSIZE,&readFds,NULL,NULL,NULL);if(nRet == -1){printf("select error.");return;}else if(nRet > 0){for(int fd=0;fd != FD_SETSIZE;++fd){if(FD_ISSET(fd,&readFds)){if(fd == nListenFd){socklen_t nLen = sizeof(ClientAddress); int client_sockfd = accept(nListenFd, (struct sockaddr *)&ClientAddress, &nLen);printf("accept %d,\r\n",client_sockfd); ClientFds.insert(client_sockfd);}else{printf("%d has thing.\r\n",fd);int nRead;//test if there some data to read;ioctl(fd, FIONREAD, &nRead);char ch; if(nRead != 0)nRead = read(fd, &ch, 1); if(nRead == 0) { close(fd); //FD_CLR(fd, &readFds); ClientFds.erase(fd);printf("removing client on fd %d\r\n", fd); } else{if(ch != '\r' && ch != '\n')printf("serving client on fd %d %c %d \r\n", fd,ch,ch); } }}}}else{printf("select time out");return;}}}

2.实现对fd的time read

int Read(int fd, char * pBuffer, unsigned int nBufferLend, unsigned int nMillisecondTimeOut){struct timeval TimeOut;TimeOut.tv_sec  = nMillisecondTimeOut / 1000;TimeOut.tv_usec = (nMillisecondTimeOut%1000)*1000;int nReadLen = 0;char* ptr = pBuffer;fd_set readFds;FD_ZERO(&readFds);FD_SET(fd,&readFds);while(nReadLen < nBufferLend){int nRet = select(fd+1,&readFds,NULL,NULL,&TimeOut);if(nRet == -1){nReadLen = -1;perror("select error");break;}else if(nRet > 0){nRet = read(fd,ptr,1);printf("remain time,sec: %d,usec: %d\n",TimeOut.tv_sec,TimeOut.tv_usec);if(nRet < 0){perror("read err:");break;}else if(nRet == 0)break;nReadLen += nRet;ptr += nRet;}else{nReadLen = -1;printf("timeout!\n");break;}}return nReadLen;}





0 0