Linux高阶IO之select多路转接

select多路转接

多路转接有三种方案,分别是select,poll和epoll,我们都会讲解和介绍

select的函数原型是这样的

在这里插入图片描述

他一共有五个参数,但是可以分为三组

  • nfds:需要监视的最大的文件描述符值+1
  • readfds:可读文件描述符集合
    writefds:可写文件描述符集合
    exceptfds:异常文件描述符集合
  • timeout:设置select等待的时间

就绪事件分为三种,可读事件,可写事件,异常事件

timeout

select可以帮我们同时等待多个文件描述符,但是如果一直轮询多个描述符是不合理的,我们应当可以设置他阻塞或者轮询

因此timeout可以传入三种数据

  • NULL : 表示没有timeout,select一直阻塞等待,直到有了就绪的文件描述符
  • 0 : 进检测文件描述符集合的状态,然后立即返回,不会进行任何阻塞等待,继续执行后面的逻辑
  • 确定的时间 : 阻塞指定的时间段,没有等到则超时返回

前两个都好理解,第三个的数据类型是timeval,要怎么用呢

他的内部有两个成员,分别对应了秒和微秒

长这样

struct timeval {
    __time_t      tv_sec;  // 秒
    __suseconds_t tv_usec; // 微秒
};

使用的时候需要线对他进行初始化,然后传入select即可

struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 500;
// 等待1.5秒

fd_set

fd_set是中间三个文件描述符的类型,如果你了解信号,也一定猜到,这个fd_set是一共位图,你可以将你期待监视的文件描述符设置到这个位图中然后传递进去

但是我们不能直接操作这个数据结构,需要使用下面的函数,分别对应着删除\测试\设置\置零

在这里插入图片描述

返回值

select的返回值需要区分

  • 执行成功 : 返回文件描述符状态改变的个数
  • 0 : 阻塞等待超时
  • -1 : 出错了,错误原因在errno里,此时三个输出型参数的值是未知的

错误原因可能有

  • EBADF : 文件描述符无效或者文件描述符关闭
  • EINTR : 调用被信号中断
  • EINVAL : n为负值
  • ENOMEM : 核心内存不足

执行过程

其实最后一个参数timeout也是输出型参数

当你设置阻塞时间为5秒,等了3秒后时间就绪了,函数就返回了,timeout的时间就会变成2秒

fd_set也是这样的,我们把想要监视的文件描述符放在fd_set中,但是他返回的时候,只有就绪的文件描述符返回出来了,如果一开始设置了0,1,2,3,4,之后0和3就绪了,那么我们再拿到对应的fd_set,就只能读到0和3,原来的fd_set就消失了一样

因此如果我们想要循环进行select,每一次都需要重置过参数

总结

select能够同时监视多个文件描述符,但是也总是有上限的,上限就是fd_set位图的大小

除此之外,我们不仅需要维护fd_set,还需要额外维护放入fd_set中的数据集,否则我们无法使用FD_ISSET判断文件描述符是否就绪

而且每一次都需要重新逐一加入fd_set,然后再取出最大的文件描述符,作为第一个参数输入

所以这个系统调用是真难用,非常不便,还需要将fd_set从用户态拷贝到内核态,fd_set也不够大

但是这是第一个,有缺陷才是正常的,后面才会越来越好,有了poll和epoll

具体使用select写server的代码可以来我的github仓库来看看

LearnRep/CppCode at main · Ye-Yu-Mo/LearnRep (github.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

栖林_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值