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;
}

本文介绍了一种基于select机制的简单服务器模型,用于处理多个客户端连接请求,并通过实例展示了如何利用select进行文件描述符(fd)的检测,以及如何实现带超时的读取操作。
4144

被折叠的 条评论
为什么被折叠?



