I/O复用之select
select函数注意事项
#include<sys/select.h>
#include<sys/time.h>
int select (int maxfd,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval * timeout)
关于I/O复用之select函数,函数原型和头文件已经给出,具体参数含义就不再赘述。不太熟悉的可以参考UNIX网络编程卷一(socket编程)这本书。本文主要讲下在使用过程中需要注意的事项。
一、返回值
select返回值为int整型,如果监听的多个文件描述符就绪(即你所关心的可读或可写或异常),则返回就绪的描述符个数。如果设定了timeout时间,则如果时间到达之前并没有文件描述符就绪,则返回0。如果当时间未到达或未设置时间(最后一个参数为NULL),此时监听项还未就绪,select理应阻塞,但由于此时有信号过来,则此时任何阻塞的系统调用都将被唤醒,此时,select返回-1.
二、time值
1、如果上述timeout为NULL,则select会阻塞直至监听项就绪。
2、如果timeout中的秒和微妙都设置为0,则此时select检查完描述符后立即返回,这就是轮询。
3、time值在大多数情况下在函数返回时不会被select修改,但真的是根据操作系统不同而不同的。笔者所用的centos7就会被select修改成该函数返回时剩余的秒数,因此,为了代码的健壮性,建议大家在每一次调用select之前都对timeout重新赋值。
三、 fd_set变化
当select函数调用完成后,向其传递的fd_set变量将发生变化。描述符集内的任何与未就绪描述符对应的位均清成0.
怎样理解这句话呢,请看下图:
此时,select所监听的项每一次都就绪,所以对应的位仍为1,但如果在时间结束后,还未就绪,则对应的位会被清成0!
如下图:
所以,我们在每一次调用select的时候,仍需要通过FD_SET宏,在fd_set所指向的变量中注册监听项的文件描述符。