Linux常见IO模型

本文详细介绍了Linux中的五种IO模型:阻塞IO、非阻塞IO、信号驱动IO、异步IO以及多路转接模型(如select、poll、epoll),分析了各种模型的优缺点及其实现机制,特别讨论了多路转接模型在高并发场景下的应用和select接口的使用方法。
摘要由CSDN通过智能技术生成

这篇博客开始我们Linux的最后一个章节--常见IO模型,在之前的博客当中我们讲述过Linux中基础的IO操作,欢迎大家去阅读。

我们通常指的IO操作便是数据的输入和输出,对应的具体操作过程我们可以将其分为两个步骤:等待IO就绪和数据拷贝,那么针对这两个方面我们设计出了一些相关的IO模型。

目录

1.阻塞IO

1.1内容

1.2优缺点

2.非阻塞IO

2.1内容

2.2优缺点

3.信号驱动IO

3.1内容

3.2优缺点

4.异步IO

4.1内容

4.2优缺点

5.多路转接模型

5.1内容

5.2优点

5.3实现

5.3.1接口介绍

5.3.2代码实现

1.阻塞IO

1.1内容

阻塞IO是指:发起IO操作之后,如果当前不具备IO操作的条件,则进程等待直到条件满足后再进行IO操作。

1.2优缺点

这样做有很明显的优点便是:实现流程简单;但是缺点同样也很突出,即:资源利用率低下,会占用进程,效率较低。

2.非阻塞IO

2.1内容

非阻塞IO是指:发起IO操作之后,如果当前具备IO操作的条件,则完成IO操作后返回,若不具备条件,则直接报错返回。可是这样简单进行判断的话,该怎么保证我们的IO操作可以被进行呢。程序中设计给出的答案是--循环,加入循环,对IO条件不断进行判断,直到执行。

2.2优缺点

这样操作的优点是:资源利用率高(不进行IO操作时,进程可以被分配完成其他任务);缺点也正是创造它优点的部分,即:需要进行循环操作,流程变的复杂,代码设计难度提x

值得注意的是,我们设计非阻塞IO的目的是:在等待IO条件满足时可以让进程完成其他任务,但这样的操作也会有一定的缺陷,那就是文件IO操作并不会是实时的了。也就是说,如果某一时间IO条件满足,但进程被分配的其他任务并没有完成,那么进程在完成该任务后,才会进行对应的IO操作。

3.信号驱动IO

3.1内容

信号驱动IO是指:定义IO信号的处理方式,IO就绪通过信号通知,打断进程当前操作,然后发起对应的IO调用。

3.2优缺点

信号驱动IO是在非阻塞IO的基础上进行设计的,是为了解决非阻塞IO无法确保实时处理IO操作的问题,因此它的优点也就呼之欲出,即:对资源利用更加充分,能更好的把控进程,并且对IO的操作是实时的;缺点也很明显:代码复杂度进一步提高,流程更加复杂。

4.异步IO

4.1内容

异步IO是指:发起异步IO操作,IO的等待以及数据的拷贝都有系统完成,完成之后通知进程。

4.2优缺点

异步IO的提出,让我们对资源的利用率达到的一定程度上的最高,我们只需要完成操作内容的通知以及操作结果的接收即可,并不需要去完成具体操作,如此设计的优点也就十分明了,即:对资源的利用率提升到了最高;缺点便是:对程序的复杂度也达到了最高。

5.多路转接模型

5.1内容

多路转接模型是一种高效的IO多路复用技术,使得单个进程能够处理多个IO事件,常用于高并发服务器技术的使用,让我们可以针对大量描述符进行IO就绪事件监控。

5.2优点

  • 让进程能够针对就绪的描述符进行IO操作,提高了任务的处理效率;
  • 避免进程因为对于未就绪描述符进行操作,而导致阻塞的情况。

5.3实现

多路转接模型的具体实现案例有很多,例如:select、poll和epoll等。我们针对select模型进行讲述,对于select模型而言,IO事件被分为三类:可读事件、可写事件和异常事件。它的主要流程思想是:

  • 定义指定IO事件的描述符集合;
  • 将需要对指定事件进行监控的描述符添加到指定集合当中;
  • 将事件的描述符集合拷贝到内核当中,进行事件监控;
  • 对集合中所有的描述符进行一次遍历,若没有就绪内容则将描述符挂到内核IO事件队列当中;
  • 若监控过程中,某一描述符就绪了所要监控的事件,则唤醒进程的阻塞;
  • 被唤醒后,select会再次将描述符集合遍历一遍,将集合中没有就绪的描述符移除;
  • 上三步完成监控后,只需要判断那一个描述符在集合当中,则该描述符就就绪了一个事件;
  • 于是进程可以根据就绪不同的事件对描述符进行不同的IO操作。

5.3.1接口介绍

Ⅰ、定义集合:

fd_set set;

本质上该集合是一个比特位图,默认拥有1024个比特位,取决于__FD_SETSIZE,因此select对描述符进行IO监控,存在有最大数量限制。

Ⅱ、初始化集合,将需要监控的描述符添加到集合当中:

void FD_ZERO(fd_set *set);//初始化清空集合
void FD_SET(int fd, fd_set *set);//将fd描述符添加到set集合当中
void FD_CLR(int fd, fd_set *set);//将fd描述符从set集合当中删除

Ⅲ、开始监听集合:

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

其中,int nfds是所有需要监控集合中,最大的描述符+1,提高遍历效率;fd_set *readfds是可读事件描述符;fd_set *writefds是可写事件描述符, fd_set *exceptfds是异常事件描述符。

struct timeval该结构体的内容如下:

struct timeval{
    time_t tv_sec;
    time_t tv_usec;
};

它的主要作用是设置本次监听阻塞时长,NULL表示一致阻塞,直到有描述符就绪或被信号打断。

select返回值为:返回实际就绪的描述符事件个数;出错返回-1;监听超时返回0(没有描述符就绪)。

Ⅳ、判断描述符在集合中,判断描述符就绪在事件中:

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

5.3.2代码实现

设计代码使用相应接口对多路转接模型的内容进行简单实现,最后得到结果如下:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值