Linux 之 IO模型

IO的本质是基于操作系统接口来控制底层的硬件之间数据传输,并且在操作系统中实现了多种不同的IO方式(模型),比较常见的有下列三种

阻塞型IO模型
非阻塞型IO模型
多路复用IO模型

一、阻塞与非阻塞IO

一般默认的 IO 操作都是阻塞型 IO,在IO操作时等待输入会阻塞进程(进入睡眠状态)资源就绪后苏醒

阻塞IO模型如下图:在这里插入图片描述
非阻塞IO:当进程发出IO请求后,进行轮询就检查操作,无论资源是否就绪都返回,直到资源就绪才处理资源,其模型如下图:
在这里插入图片描述

实现非阻塞型IO,需要设置 O_NONBLOCK 标志,两种方式:
1.调用 fcntl 函数来进行设置
2.通过open函数来进行设置,一般在打开文件时就需要设置

多路复用IO(select,poll,epoll)

简介:本质上就是通过复用一个进程来处理多个IO请求
基本思想由内核来监控多个文件描述符是否可以进行I/O操作,如果有就绪的文件描述符,将结果告知给用户进程,则用户进程再进行相应的I/O操作

目前在Linux系统有三种多路复用I/O的方案:
select、poll、epoll

Select

设计思想通过单进程创建一个文件描述符集合,将需要监控的文件描述符添加到这个集合中,由内核负责监控文件描述符是否可以进行读写,一旦可以读写,则通知相应的进程进行相应的I/O操作

原型
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds,
struct timeval *timeout);
功能
监控一组文件描述符,阻塞当前进程,由内核检测相应的文件描述符是否就绪,一旦有文件描述符就绪,将就绪的文件描述符拷贝给进程,唤醒进程处理
参数
nfds:最大文件描述符加1
readfds:读文件描述符集合的指针
writefds:写文件描述符集合的指针
exceptfds:其他文件描述符集合的指针
timeout:超时时间结构体变量的指针
函数返回值
成功:返回已经就绪的文件描述符的个数。如果设置timeout,超时就会返回0
失败:-1,并设置errno

操作文件描述符集合函数
void FD_CLR(int fd,fd_set *set)
将fd从文件描述符集合中删除

int FD_ISSET(int fd,fd_set *set)
判断fd是否在文件描述符集合中

void FD_SET(int fd,fd_set *set)
将文件描述符添加到文件描述符集合中

void FD_ZERO(fd_set *set)
将文件描述符集合清空
参数描述:
fd:文件描述符
set:文件描述符集合的指针

超出时间说明:
如果timeout之后,文件描述符集合中没有任何就绪的文件描述符,select函数就会返回0
超时之后,timeout会被select函数修改,表示超时时间已经使用完。
如果想继续使用超时时间,需要备份之前的struct timeval

超时之后,表示没有就绪的文件描述符,此时文件描述符集合被赋值为空。因此,需要将之前的文件描述符集合进行备份

Poll

多路复用poll的方式与select多路复用原理类似,但有很多地方不同。

区别:
1.在应用层是以结构体struct pollfd数组的形式来进行管理文件描述符,在内核中基于链表对数组进行扩展;select方式以集合的形式管理文件描述符且最大支持1024个文件描述符
2.poll将请求与就绪事件通过结构体进行分开;select将请求与就绪文件描述符存储在同一个集合中,导致每次都需要进行重新赋值才能进行下一次的监控
共同点:在内核中仍然使用的是轮询的方式,与 select 相同,当文件描述符越来越多时,则会影响效率

使用:
原型:int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数:
fds:sturct pollfd结构体指针
nfds:fds结构体的数量
timeout:超时时间,单位为ms
返回值:
成功:大于0,返回就绪的文件描述符数量;=0,超时返回,没有文件描述符就绪
失败:-1,并设置errno

在这里插入图片描述

Epoll

select/poll的不足:
1.select 方案使用数组存储文件描述符,最大支持1024个
2.select 每次调用都需要将文件描述符集合拷贝到内核中,非常消耗资源
3.poll 方案解决文件描述符存储数量限制问题,但其他问题没有得到解决
4.select / poll 底层使用轮询的方式检测文件描述符是否就绪,文件描述符越多,则效率越低

epoll优点
1.epoll底层使用红黑树,没有文件描述符数量的限制,并且可以动态增加与删除节点,不用重复拷贝
2.epoll底层使用callback机制,没有采用遍历所有描述符的方式,效率较高

使用epoll_create函数创建:

原型:int epoll_create(int size);
参数:size:需要填一个大于0的数,从Linux 2.6.8开始,size参数被忽略
返回值:成功返回epoll文件描述符,失败返回-1,并设置errno

示例代码:创建一个epoll 实例
在这里插入图片描述

epoll控制函数:
主要用于文件描述符集合的管理,包括增加、修改、删除等操作。

原型:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
参数
epfd:epoll 实例
op:epoll 操作命令字
EPOLL_CTL_ADD:在epoll实例中添加新的文件描述符(相当于向红黑树中添加节点),并将事件与fd关联
EPOLL_CTL_MOD:更改与目标文件描述符fd相关联的事件
EPOLL_CTL_DEL:从epoll实例中删除目标文件描述符fd ,事件参数被忽略
fd:操作的文件描述符
event:struct epoll_event结构体对象指针

epoll 等待函数
epoll 等待事件发生(关联的文件描述符就绪)

原型:
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int
timeout);
参数:
epfd:epoll实例对象
events:存储就绪集合的数组的地址
maxevents:就绪集合的最大值
timeout:超时时间
返回值:
成功:返回就绪的文件描述符数量,超时返回0
失败:返回-1,并设置errno

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值