【Linux】高级IO
目录
IO的本质
五种IO模型
非阻塞IO
fcntl
多路转接IO
select
参数介绍
代码示例
select缺点
poll
参数介绍
代码示例
epoll
优点
接口
原理
代码
epoll工作模式
LT与ET
基于epoll的ET模式的Reactor
Reactor项目
IO的本质
五种IO模型
张三一直盯着鱼鳔,直到有鱼咬钩
李四每间隔一段时间看一次鱼鳔,其它时间在刷手机
王五的鱼竿有铃铛,鱼咬钩会响铃,其它时间在刷手机
赵六有10根鱼竿,轮询检测鱼鳔
田七是老板,他让秘书帮他钓,钓满一桶后通知老板
非阻塞IO
fcntl
这个接口的作用是对文件描述符进行操作
我们如何通过fcntl把某一个文件描述符对应的flag设置成非阻塞?
先用fcntl的getfl获得该文件描述符的flag,再用fcntl的setfl把获得的flag进行设置
返回值为-1,错误码为11(EWOULDBLOCK)表面不是真的出错而是底层没就绪
多路转接IO
select
参数介绍
返回值:大于0表示有返回值个fd就绪,等于0表示超时,没错误但也没就绪,小于0表示出错
第一个参数是要等的文件描述符中最大的文件描述符加1,比如要等1,2,3,那么第一个参数就是3+1
第二,三,四个参数
如果你想关心某一个fd的读事件,那么就在第二个参数位图里面对应位置置1,如果关心写事件就在第三个参数里,第四个参数是异常事件,可关心多个事件
这些位图参数也是输入输出参数,用户给位图置1然后告诉操作系统置1的地方你要关心,操作系统也返回一个位图,告诉用户里面置1的地方已经就绪了
fd位图操作接口
FD_CLR:置0指定fd
FD_ISSET:判断指定fd是否为1
FD_SET:置1指定fd
FD_ZERO:全部置0
第五个参数是一个结构体,负责select的等待时间
还是输入输出参数,比如我设了等待5秒,但是2秒就就绪了,那么会返回5-2秒
代码示例
select监视fd
accept本质需要等待新连接到来,可以看作等待读事件就绪,等的过程就可以交给select
等待时间需要重复设置,因为是输入输出参数导致会保留上一次的剩余时间
等待时间设为nullptr表明一直阻塞等待
处理就绪fd
连接事件就绪,可以直接获取连接了,这样accept不会阻塞直接获取连接
通过辅助数组实现fd的传递,交给select管理
通过遍历辅助数组把对应fd集位置置1,并获得最大fd值
把新的fd加入辅助数组中
完整代码
advance_io_lesson/select · lyh/linux - 码云 - 开源中国
select缺点
poll
参数介绍
poll相当于是select的优化版, poll解决了select的fd有上限的问题,解决了不用每次都维护fd位图集的问题
poll和select共同点:都需要遍历“维护fd”的辅助数组,在内核中遍历检测哪些fd就绪,在用户层遍历检测哪些事件就绪
第一个参数是结构体数组
结构体表示在该fd下,events表示用户要内核关心的事件,revents表示内核告诉用户哪些事件就绪了
short有16个比特位,最多可以表示16种事件
第二个参数表示数组的大小,也就是要关心的fd的个数
第三个参数是等待事件,单位是毫秒
代码示例
内核告诉用户的事件就绪是内核自动写的,用户不用操作了(revents)
poll的代码和select不同点:
成员变量由原本的fd辅助数组改为pollfd结构体数组
构造函数对数组的初始化变了
接口由select改为poll
判断事件就绪改变了,原本用户和内核共用一个位图集交流,现在在结构体里面分开维护了
插入新fd的时候要改为插入整个结构体
完整代码
advance_io_lesson/poll · lyh/linux - 码云 - 开源中国
epoll
优点
epoll是poll的加强版,但是epoll和poll的代码没有相似度,不像poll和select
用户只需要关心就绪队列是否为空,空就是无就绪,非空就是有就绪,再遍历就绪队列把就绪结点一个一个插入到自己维护的结构体数组中
接口
创建一个epoll模型
epoll模型也被当成文件接入了文件模块并且有自己的fd
参数已废弃,大于0就行,返回值是一个fd
获取就绪队列
第一个参数填epoll_create的返回值
第二个参数输出型,是一个结构体数组,会把就绪队列的结构体依次插入数组中
事件
第三个参数是数组最大个数
第四个参数是等待时间,单位是毫秒
返回值
操作红黑树
第一个参数填epoll_create的返回值
第二个参数是选项,增加,修改,删除
第三个参数,要操作哪一个fd
第四个参数,要操作该fd的哪些事件
原理
网卡硬件(物理层)有数据并且就绪了会发生硬件中断,告诉网卡驱动(数据链路层)把数据拿上去,网卡驱动数据就绪了就会调用回调函数,回调函数的作用:向上交付数据给tcp的接收缓冲区(接收队列),查找红黑树查找与这些数据关联的fd以及对应关心事件是否符合,符合就构建就绪结构体插入到就绪队列中
操作系统维护了一颗红黑树,树的结点是结构体,结构体里面有fd和关心事件
操作系统维护了一条就绪队列,当有事件就绪,操作系统就会构造一个结构体连入就绪队列中,这个结构体包含fd和就绪事件
epoll模型
代码
advance_io_lesson/Epoll_Server · lyh/linux - 码云 - 开源中国
epoll工作模式
LT与ET
ET就是每当有新事件来就提醒一次,LT有事件就一直提醒处理
为什么ET都要非阻塞?
因为ET必须一次把数据全部取走,势必会读到空,这时默认是阻塞
ETLT效率取决代码实现
一次取走全部数据,剩余空间就更大
ET与LT本质是一个只在就绪队列添加一次,一个是每次都添加
基于epoll的ET模式的Reactor
Reactor理论
Reactor反应堆是这个游戏面板,每一个洞就是连接对象,下锤子就是调用处理方法
同步体现在select/poll/epoll上,它们要参与等的过程(IO=等+拷贝)
Reactor项目
advance_io_lesson/Reactor · lyh/linux - 码云 - 开源中国