Select函数:允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或经历一段指定的时间后才唤醒它。
![c3fc43cfb211b4b49ee9c22e60b19cf5.png](https://i-blog.csdnimg.cn/blog_migrate/621f6a64e88d37675b78ab7a762b0ea5.jpeg)
select man手册
举个栗子,我们可以调用Select,告诉内核仅仅在下列情况发生时才返回:
- 集合{1,4,5}中任何描述符准备好读集合{2,7}中任何描述符准备好写集合{1,4}中任何描述符由异常条件待处理已经经历了10秒
我们调用Select告诉内核对哪些描述符感兴趣以及等待多长时间。
/* According to POSIX.1-2001 */ #include /* According to earlier standards */ #include #include #include int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
int nfds 指定待测试的描述符个数,它应该被设置为待测试的最大数目+1。fd_set通常支持的最大描述符是1023+1。
如何设置下面3个参数中的每个参数指定一个还是多个描述符值是一个设计上的问题。select采用描述符集,通常是一个整数数组,其中每个整数中的每一位对应一个描述符。
举个栗子:假设使用32位整数,那么该数组的每一个元素对应于描述符0-31,第二个元素对应于描述符32-63,以此类推。
#include /* According to earlier standards */ #include #include #include void FD_CLR(int fd, fd_set *set); int FD_ISSET(int fd, fd_set *set); void FD_SET(int fd, fd_set *set); void FD_ZERO(fd_set *set);
我们可以分配一个fd_set数据类型的描述符集,并用这些宏设置或测试该集合中的每一位。
举个栗子:我们定义一个fd_set类型的变量,然后打开描述符1、4、5对应的位。
fd_set rset;FD_ZERO(&rset);FD_SET(1,&rset);FD_SET(4,&rset);FD_SET(5,&rset);
如果对readset、writeset、exceptset中的某一个条件不感兴趣,我们可以把它设置为空指针。
fd_set *readfds 指定让内核测试读条件的描述符fd_set *writefds 指定让内核测试写条件的描述符
- fd_set *exceptfds 指定让内核测试异常条件的描述符
目前支持的异常条件:
某个套接字的带外数据到达。某个已设置为分组模式的伪终端存在可从其主端读取的控制状态信息。
- struct timeval *timeout
struct timeval { long tv_sec; /* seconds */ long tv_usec; /* microseconds */};
把该参数设置为NULL,阻塞,仅在有一个描述符准备好IO时才返回。tv_sec != 0 || tv_usec != 0 ,超时返回,或在有一个描述符准备好IO时返回。tv_sec == 0 || tv_usec == 0 ,立即返回,这称为轮训。
select函数修改由指针readset,writeset,exceptset所指向的描述符集,这3个参数都是值-结果参数。调用的时候,我们指定所关心的描述符值。返回的时候,结果将指示这些描述符已经就绪。函数返回后,我们使用FD_ISSET宏测试fd_set数据类型中的描述符。
小测试: