网络(三)——Linux下的5种IO模型

什么是I/O模型:

通常情况下I/O操作是比较耗时的,所以为了高效的使用硬件,应用程序可以专门设置一个线程进行I/O操作,而另外一个线程则利用CPU的空闲去做其他计算,这种为提高应用执行效率而采用的I/O操作方法称为I/O模型;

当然了,在网络里面就要变通一下,不在是对硬件执行I/O操作,而是对网络上的数据,示意图如下:
在这里插入图片描述
阻塞和非阻塞就体现在从内核空间拷贝数组到用户空间的过程中线程的调用者的状态,同步与异步的区别就在于是否是由调用方自己来拷贝数组;

  • 同步:调用发出之后,事件发生后,被调用方会通知调用者亲自来处理;
  • 异步:调用发出之后,调用方就不管了,被调用方立即返回反馈,但是反馈的并非最终结果,被调用者要通过状态、通知机制、回调函数等来处理返回结果,也就是调用发出之后就不归调用方自己去处理的就是异步;
  • 阻塞:调用结果返回之前,调用方会阻塞,调用者只有在拿到结果之后才能继续后面的其他操作;
  • 非阻塞:调用结果返回之前,调用者不会挂起,即调用不会阻塞调用者;

同步和异步关注的是:消息通知机制,也就是被调用者如何通知调用者;同步和异步是相对于操作结果来说,会不会等待结果返回;
阻塞和非阻塞关注的是:调用者等待被调用者返回结果时的状态;

那么上面两步操作组合起来就有以下四种对应的I/O模型:
①同步阻塞(比如BIO模型)
①同步非阻塞(NIO模型)
③异步阻塞
④异步非阻塞(AIO)

Unix中存在的5中I/O模型:

因为服务器一般都是放在Linux系统上的

  • 同步阻塞I/O:就是一直在那等数据,数据到了,自己完成拷贝
  • 同步非阻塞I/O:如果数据没到,它先干其他的事,过一会去问一下操作系统,数据到了没,没到继续先去干其他的事,过一会又来问,直到数据到了,完成拷贝;
  • I/O复用:托多路选择复用器帮自己看着,自己先回去干其他事,数据来了多路选择复用器通知自己,自己去完成拷贝;
  • 信号量:自己先去看一下,如果数据没到,自己先回去干其他事,如果数据来了,操作系统通知自己去完成拷贝;
  • 异步I/O:如果数据没到,让其他线程帮忙看着,数据到了,让它完成拷贝,自己啥都不用管;

1、同步阻塞I/O

同步阻塞 IO 模型是最常用的一个模型,也是最简单的模型。在linux中,默认情况下所有的socket都是blocking。它符合人们最常见的思考逻辑。

在这个IO模型中,用户空间的应用程序执行一个系统调用(recvform),这会导致应用程序阻塞,什么也不干,直到数据准备好,等待kernel准备好从网络上接收到的数据报 + 等待收到的报文被从kernel复制到buf中,recvfrom方法才会返回,最后进程再处理数据。

这就是阻塞式IO模型
在这里插入图片描述

2、同步非阻塞式I/O

非阻塞IO时对一个非阻塞描述符循环调用recvfrom,持续的轮询(polling),以查看某个操作是否就绪。与阻塞IO不一样,“非阻塞将大的整片时间的阻塞分成N多的小的阻塞, 所以进程不断地有机会 ‘被’ CPU光顾”。

非阻塞的recvform系统调用之后,进程并没有被阻塞,内核马上返回给进程,如果数据还没准备好,此时会返回一个error。进程在返回之后,可以干点别的事情,然后再发起recvform系统调用。如此循环的进行recvform系统调用,检查内核数据,直到数据准备好,再拷贝数据到进程。拷贝数据整个过程,进程仍然是属于阻塞的状态。

这就是非阻塞式IO模型
在这里插入图片描述

3、I/O复用

IO multiplexing就是我们说的select,poll,epoll 。为何叫多路复用,是因为它I/O多路复用可以同时监听多个fd,如此就减少了为每个需要监听的fd开启线程的开销。

select调用是内核级别的,可以等待多个socket,能实现同时对多个IO端口进行监听,当其中任何一个socket的数据准好了,就能返回进行可读,然后进程再进行recvform系统调用,将数据由内核拷贝到用户进程,这个过程是阻塞的。

I/O复用模型会用到select、poll、epoll函数,这几个函数也会使进程阻塞,但是和阻塞I/O所不同的的,这几个函数可以同时阻塞多个I/O操作。而且可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写时(不是等到socket数据全部到达再处理, 而是有了一部分数据就会调用用户进程来处理),才真正调用I/O操作函数。

IO复用有人把其称为为同步非阻塞的,也有称为同步阻塞。其实这个是否阻塞还需要看第一个阶段,第一个阶段有的阻塞,有的不阻塞。主要也是阻塞在select阶段,属于用户主动等待阶段,我们且规范为阻塞状态,所以,把IO多路复用归为同步阻塞模式。

这是IO复用的模型:

在这里插入图片描述
select、poll、epoll的不同:

selectpollepoll
单个进程所能打开的最大连接数有FD_SETSIZE定义,其大小是32的正数倍大小(32位机上是32×32,64位机上是32×64),当然我们可以对其进行修改,然后重新编译内核,但是性能可能会受影响poll本质上和select没什么区别,但他没有最大连接数的限制,因为它是基于链表来存储的虽然连接数有上限,但是很大, 1G内存的机器上可以打开10万左右的链接,2G内存的机器上可以打开20万左右的链接

4、信号驱动式I/O

信号驱动式I/O:首先我们允许Socket进行信号驱动IO,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据。

也就是说第一个阶段,完全是非阻塞的,等数据到达会给一个信号通知,第二个阶段recvfrom还是阻塞过程,和之上无差异。

信号驱动式I/O 过程如下:
在这里插入图片描述

5、异步I/O

异步IO不是顺序执行,用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知。IO两个阶段,进程都是非阻塞的。
在这里插入图片描述
解释:
比如现在小明要参加一个演唱会,他从家到售票点买票,售票员告诉小明,现在还没开始卖票呢,那么他与I/O模型相对应的有以下5种解决方法:
①同步阻塞I/O
小明直接在售票点等待第二天早上然后买票,去看演唱会;
②同步非阻塞I/O
小明直接回家去干其他事了,然后过一会儿就来问一次,开始卖票了吗,如果没有小明又回家,过一会继续来询问,直至开始卖票,小明买到票,去看演唱会;
③I/O复用
小明打电话给黄牛,让他帮忙留意票出来了没,出来的话通知一下自己,(注意,这个黄牛不但可以帮助小明留意这个事情,还可以帮助其他的很多人),然后自己去买票,看演唱会;
④信号量
小明直接给举办方留了电话就回家了,并给举办方说,如果票出来了,给我打电话,然后小明去买票,看演唱会;
⑤异步I/O
小明找到一个快递员,给他说,你在这帮我看着,如果票出来了,帮我买了,然后送给我,我去看演唱会,自己就直接回家了;

总结

针对这5中IO模型,我采用一张图来总结一下。
在这里插入图片描述
java中的IO模型:BIO、NIO、AIO

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值