IO多路复用——select函数

1.select函数原型和fd_set结构体说明

1.1 select函数原型

​ 使用 select 这种 IO 多路转接方式需要调用一个同名函数 select,这个函数是跨平台的,Linux、Mac、Windows 都是支持的。程序员通过调用这个函数可以委托内核帮助我们检测若干个文件描述符的状态,其实就是检测这些文件描述符对应的读写缓冲区的状态:

  • 读缓冲区:检测里边有没有数据,如果有数据该缓冲区对应的文件描述符就绪
  • 写缓冲区:检测写缓冲区是否可以写 (有没有容量),如果有容量可以写,缓冲区对应的文件描述符就绪
  • 读写异常:检测读写缓冲区是否有异常,如果有该缓冲区对应的文件描述符就绪

委托检测的文件描述符被遍历检测完毕之后,已就绪的这些满足条件的文件描述符会通过 select() 的参数分 3 个集合传出,程序猿得到这几个集合之后就可以分情况依次处理了。

#include <sys/select.h>
struct timeval {
    time_t      tv_sec;         /* seconds  秒 */  
    suseconds_t tv_usec;        /* microseconds   微妙*/
};

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval * timeout);
  • 函数参数:
    • nfds:委托内核检测的这三个集合中最大的文件描述符 + 1 **三个集合指的是:**readfds writefds exceptfds 读写异常三个集合,里面有很多文件描述符,找出最大的+1
      • 内核需要线性遍历这些集合中的文件描述符,这个值是循环结束的条件
      • 在 Window 中这个参数是无效的,指定为 - 1 即可
    • readfds:文件描述符的集合,内核只检测这个集合中文件描述符对应的读缓冲区
      • 传入传出参数,读集合一般情况下都是需要检测的,这样才知道通过哪个文件描述符接收数据
    • writefds:文件描述符的集合,内核只检测这个集合中文件描述符对应的写缓冲区
      • 传入传出参数,如果不需要使用这个参数可以指定为 NULL
    • exceptfds:文件描述符的集合,内核检测集合中文件描述符是否有异常状态
      • 传入传出参数,如果不需要使用这个参数可以指定为 NULL
    • timeout:超时时长,用来强制解除 select () 函数的阻塞的
      • NULL:函数检测不到就绪的文件描述符会一直阻塞。
      • 等待固定时长(秒):函数检测不到就绪的文件描述符,在指定时长之后强制解除阻塞,函数返回 0
      • 不等待:函数不会阻塞,直接将该参数对应的结构体初始化为 0 即可。
  • 函数返回值:
    • 大于 0:成功,返回集合中已就绪的文件描述符的总个数
    • 等于 - 1:函数调用失败
    • 等于 0:超时,没有检测到就绪的文件描述符

1.2 fd_set结构体说明

​ 在 select() 函数中第 2、3、4 个参数都是 fd_set 类型,它表示一个文件描述符的集合,类似于信号集 sigset_t,这个类型的数据有 128 个字节,也就是 1024 个标志位,和内核中文件描述符表中的文件描述符个数是一样的。

sizeof(fd_set) = 128 字节 * 8 = 1024 bit      
// fd_set类似一个32内存的int [32]数组,但是操作是按标志位bit为单位进行的

​ 这并不是巧合,而是故意为之。这块内存中的每一个 bit 和 文件描述符表中的每一个文件描述符是一一对应的关系,这样就可以使用最小的存储空间将要表达的意思描述出来了。

下图中的 fd_set 中存储了要委托内核检测读缓冲区的文件描述符集合。

  • 如果集合中的标志位为 0 代表不检测这个文件描述符状态
  • 如果集合中的标志位为 1 代表检测这个文件描述符状态

在这里插入图片描述

​ 内核在遍历这个读集合的过程中,如果被检测的文件描述符对应的读缓冲区中没有数据,内核将修改这个文件描述符在读集合 fd_set 中对应的标志位,改为 0,如果有数据那么这个标志位的值不变,还是 1。

在这里插入图片描述

​ 当 select() 函数解除阻塞之后,被内核修改过的读集合通过参数传出,此时集合中只要标志位的值为 1,那么它对应的文件描述符肯定是就绪的,我们就可以基于这个文件描述符和客户端建立新连接或者通信了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Unknown To Known

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值