转载:select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET
select函数用于在非阻塞中,当一个套接字或一组套接字有信号时通知你,系统提供select函数来实现多路复用输入/输出模型,原型: 所在的头文件为:#include<sys/time.h> 和#include<unistd.h> 先对函数中的参数做一个简单的介绍。参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集合及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。 对于fd_set类型通过下面四个宏来操作: UNIX系统通常会在头文件<sys/select.h>中定义常量FD_SETSIZE,它是数据类型fd_set的描述字数量,其值通常是1024,这样就能表示<1024的fd。 功能:测试指定的fd可读?可写?有异常条件待处理? 对于select函数的功能简单的说就是对文件fd做一个测试。测试结果有三种可能: 返回值:返回对应位仍然为1的fd的总数。注意啦:只有那些可读,可写以及有异常条件待处理的fd位仍然为1。否则为0哦。举个例子,比如recv(),在没有数据到来调用它的时候,你的线程将被阻塞,如果数据一直不来,你的线程就要阻塞很久.这样显然不好。所以采用select来查看套节字是否可读(也就是是否有数据读了)。 socket s; ..... fd_set set; while(1) { FD_ZERO(&set);//将你的套节字集合清空 FD_SET(s, &set);//加入你感兴趣的套节字到集合,这里是一个读数据的套节字s select(0,&set,NULL,NULL,NULL);//检查套节字是否可读, //很多情况下就是是否有数据(注意,只是说很多情况),这里select是否出错没有写 if(FD_ISSET(s, &set) //检查s是否在这个集合里面, { //select将更新这个集合,把其中不可读的套节字去掉,只保留符合条件的套节字在这个集合里面 recv(s,...); } //do something here } 理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。 (3)若再加入fd=2,fd=1,则set变为0001,0011 基于上面的讨论,可以轻松得出select模型的特点: (2)可以有效突破select可监控的文件描述符上限。
以下是一个测试单个文件描述字可读性的例子: int isready(intfd) { int rc; fd_set fds; struct tim tv; FD_ZERO(&fds); FD_SET(fd,&fds); tv.tv_sec = tv.tv_usec = 0; rc = select(fd+1, &fds, NULL, NULL,&tv); if (rc < 0) //error return -1; return FD_ISSET(fd,&fds) ? 1 : 0; } 上面转载文章,可查看http://blog.csdn.net/cstarbl/article/details/7645298 |