IO复用之select

select使用的是IO复用的方式进行多客户端的处理,当有客户端的连接以后会将该客户端的套接字等信息添加到队列中,然后采用轮询的方式来判断客户端是否有消息发送过来.如果客户端断开,重置队列信息,关闭套接字.

因为是使用轮询的方式进行,所以在较多客户端下速度会较慢,而且受到Linux文件描述符的数量的限制,建议在中低并发量中使用.

同样的select也有一般的形式:

int main(int argc,char *argv[])
{
int listenfd;          //监听套接字
fd_set current_fds,bak_fds;  //select的队列
int ret;            //判断返回值是否正确
int maxfds;          //最大连接数
int i;              //用于轮询的循环计数
int fdtmp;           //当前数值最大的套接字,用来减少轮询的数量

// 创建监听描述符
listenfd = create_tcp_server(8888);
if (listenfd < 0) {
perror("create tcp server failed!");
exit(-1);
}

/*初始化队列*/
FD_ZERO(&bak_fds);      //初始化队列
FD_SET(0,&bak_fds);       //初始化队列
FD_SET(listenfd,&bak_fds);    //将监听套接字放到队列中
maxfds = listenfd;       //将最大的套接字修改为监听套接字

//死循环来等待和处理客户端
while (1){
current_fds = bak_fds;//保险起见将队列复制一份使用

ret = select(maxfds+1, &current_fds, NULL, NULL, NULL);//启动select函数
if (ret < 0) {//判断是否成功
perror("select:");
close(listenfd);
return -1;
}

for (i = 0; i <= maxfds; i++) {//轮询
if( FD_ISSET(i,&current_fds) ){//读取相关的描述符
if (i == 0) {//标准输入输出
continue;
}
else if( i == listenfd ){//有新连接
fdtmp = process_listend(listenfd);//处理新连接
if (fdtmp < 0) {//出错
fprintf(stderr, "listenfd failed! ");
break;
}
printf("the newfd is %d ",fdtmp);
FD_SET(fdtmp,&bak_fds);//将新的客户端的描述符加入队列
if (fdtmp > maxfds) {//更新最大的描述符
maxfds = fdtmp;
}
}
else{//有信息发送过来
ret = process_message(i);//处理发送过来的信息
if (ret == 0) {//客户端断开连接
FD_CLR(i,&bak_fds);
close(i);
}
}
}
}
}

}

int process_listend(int sockfd)
{
int newfd;

newfd = accept(sockfd, NULL, NULL);
if (newfd < 0) {
perror("accept");
return -1;
}

printf("have a new connection... ");
return newfd;
}

原文地址:https://www.cnblogs.com/CHYI1/p/5493017.html