select,pselect,poll函数

来源:互联网 发布:惠普m1213nf mac驱动 编辑:程序博客网 时间:2024/05/08 02:26

select
机制:
     select实现了一种I/O复用,允许多个套接口阻塞在一个select函数上,而不是阻塞在I/O上,当在套接口集中,有一个及其以上的描述字有效时候,就会返回,这样对于阻塞在一个描述字上来说,提高了效率.
select函数
     #include <sys/select.h>
     #include <sys/time.h>
     int select(int maxfdp1, fd_set *read_set,fd_set *write_set,
                  fd_set *exceptset,const struct timeval *timeout);

功能:
     该函数允许进程等待多个描述字,当有一个或多个描述字准备好或超时的时候返回.每次返回时都要清空描述字,所以每次使用select前都要重新设置.

参数:  
     maxfdp1: 是集合中描述字的范围,即:允许等待的最大的描述字的值+1,通常为1024
     fd_set:一般指定内核测试可读可写还是异常.
     struct timeval {
          long tv_sec;  //second
          long tv_sec;  //microsecods
     };
     设置等待时间:
          1.设置为空指针:永远等下去,直到至少有一个描述字准备好.
          2.等待一段固定的时间.分别指定秒和微秒(精度没有这么高,一般为10ms的整数倍).
          3.不等待,即轮询,因此必须指向一个timeval结构,且其值必须为0
    
理解select的关键在于fd_set,对于fd_set,我们有四个函数进行设置:
     #include <sys/select.h>
     void FD_ZERO(fd_set *fdset); //对fd_set清零
     void FD_SET(int fd,fd_set *fdset);//设置对应描述字的位置为1
     void FD_CLR(int fd ,fd_set *fdset); //关闭对应描述字的位
     void FD_ISSET(int fd, fd_set *fd_set); //检测相应描述字是否有效
    
例子:
     fd_set fdset;
     FD_ZERO(&fdset);//清零
     FD_SET(fd,&fdset);//设置对应描述字有效
     select(maxfd,fdset,null,null,&timeout);//调用select,检测描述字是否可读,否则在指定时间后返回.
     当fd_set类型的三个参数都为NULL的时候,这是一个精准的定时器.
     fd_set类型是一个数组,这个数组总每一个数组的每一个位都标志着唯一一个描述字,无论你是否使用,若使用则该位置设为1.
    
缺陷:
     1.描述字的范围是有限的,最多仅可以监控0-1024;
     2.效率很低,select是线性扫描描述字
     3.select采用内核拷贝的方法,把内核描述字的消息通知给用户空间

效率低的原因:
     1.每次把描述字从用户空间拷贝到内核空间,等待select结束时再把描述字从内核空间拷贝到用户空间.
     2.select是线性扫描0-maxfd范围内的描述字,而且是周期性扫描(扫描一遍后睡眠,等待内核定时器到时进行下一次扫描),直到有描述字准备好或者到时为止.

    
     说了半天还不如来张图:
     我们假设fd_set是一个整数数组组成的标志fd的结构,那么如图:
     




以下条件满足之一时候,读准备好:
     1.套接口接收缓冲区的数据字节数大于低潮标记,不阻塞,并返回大于0的数,即准备好读的套接口.
     2.套接口读的这一半关闭,即接受了FIN标记的tcp连接,这样的套接口不阻塞并返回0,即EOF.
     3.套接口为一个监听端口且已创建的连接数不为0,对于这样的套接口的accept通常不会阻塞
     4.套接口发生了一个错误,这样的套接口不阻塞并返回-1,设置errno为错误类型
以下条件之一满足则写准备好
     1.套接口发送缓冲区的可用空间字节数大于低潮标记,不阻塞,返回可写套接口数
     2.套接口写的这一半关闭,对于这样的套接口写操作将产生一个SIGPIPE信号.
     3.套接口早先使用飞阻塞connect,并且连接已经异步建立.或者connect以失败告终.
     3.套接口中有一个错误. 


pselect:

机制:
     同select
pselect函数:
     #include <sys/select.h>
     #include <signal.h>
     #include <time.h>
     int pselect(int maxfdp1, fd_set *read_set,fd_set *write_set,
                  fd_set *exceptset,const struct timespec *timeout, const sigset_t *sigmask);
参数:
     timespec:精确到纳秒
     struct timespec {
          time_t tv_sec;
          long tv_nsec; //纳秒
     };
     sigset_t: 指向信号掩码的指针.用于阻塞信号的.

注释:
     1.在进程阻塞于select期间,如果有信号发生则select返回errno(EINTR),如果不想select被打断则使用pselect,并指定我们想阻塞的信号,等到pselect返回时候再恢复信号.
     2.pselect在效率上和select毫无差别
 
使用:
     sigset_t zeromask;
     sigemptyset(&zeromask); //清空
     sigaddset(&zeromask,SIGINT);//设置要阻塞的信号,即初始化
     pselect(.....,&zeromask);

poll
机制:
     同上.
poll函数:
     #include <poll.h>
     int poll(struct pollfd *fdarray,unsigned long nfds,int timeout);

参数:
     struct pollfd {
     int fd; //关心的描述字
     short events; //描述字上待测试的事件
     short revents; //描述字上发生的事件
     }
     nfds: fdarray的长度.
     timeout:毫秒,实际上精度为10ms

注释:
     1.该函数定义了一个pollfd结构数组,传入关心的描述字个数不受限制(无上限)
     2.该函数不像select一样每次执行完毕后将描述字清零,poll只需要设置一次pollfd数组,除非对感兴趣的描述字发生了变化.
     3.该函数效率依旧不高,依然进行线性扫描.
     4.每次进行内核空间和用户空间的数据拷贝,浪费时间和空间.
     5.poll是水平触发,即只要缓冲区还有数据就会返回.


     
0 0
原创粉丝点击