理解LInux系统下的五种IO模型

五种IO模型

对服务器进行编程的过程中,一个t套接口的输入操作一般有两个不同的阶段:

  • 等待数据准备好

  • 从内核到进程拷贝数据
    简而言之,对于一个套接口的输入操作,第一步是等待数据到达内核中的一个缓冲区中,例如在对屏幕进行打印的时候,首先是先把数据保存到标准输出缓冲区中,然后刷新输出缓冲区,即可完整打印出来内容。第二部是将数据从内核缓冲区拷贝到应用缓冲区中。
    针对这个过程,linux一共提供了五种IO模型来应对不同的需求:

  • 阻塞性IO

  • 非阻塞IO

  • I/O复用

  • 信号驱动

  • 异步IO

阻塞性IO

一个简单例子阻塞IO模型
应用进程只有在接受到返回成功的提示之后,才会处理数据。换言之,阻塞IO模型就是死等,只有你的数据准备好了,我才能收到并处理,否则就会一直阻塞在这里,继续等待。

非阻塞IO

当我们把一个套接口设置成非阻塞方式时,就通知内核:当请求的IO操作非得让进程睡眠不能完成时,不要让进程睡眠,而应返回一个错误;非阻塞IO
同样是上面的例子,如果内核空间的中的数据报没有准备好,则直接返回一个EWOLDBLOCK错误,而不是像阻塞性IO一样,直到数据报准备好之后才会给进程返回消息;应用进程会通过recvfrom调用不断地和内和交互,直到数据准备好。

IO复用

我们可以调用select和poll这两个系统调用来实现IO复用。同样现在还有epoll来实现IO复用。IO复用
从图中看,IO复用的过程和阻塞性IO相比较而言,反而多了一步在数据报没准备好的时候要返回可读条件,似乎是更麻烦了。但是也就是多了这一步,使得IO复用可以处理多个系统调用,从而实现多个服务器可以同多个客户端通信。即将多个进程I/0注册到同一管道上,这里管道会统一和内核交互。当管道中的某一个请求需要好的数据准备好之后,进程再把对应的数据拷贝到用户空间中。I/O多路转接是多了一个Select函数,多个进程的IO可以注册到同一个Select中,用户调用该SelectSelect会监听所有注册好的I/O,如果所有被监听的I/O需要的数据都没有准备好,Select调用进程会阻塞。当任意一个I/O所需要的数据准备好之后,Select调用就会返回,然后进程再通过recvfrom来进行数据拷贝。但实际上,它并未向内核注册信号处理函数,所以它并不是非阻塞的。

扫描二维码关注公众号,回复: 12811315 查看本文章

信号驱动型IO

在这里插入图片描述
通过系统调用sigaction安装一个信号处理程序,这个系统调用会立即返回,进程会继续工作。当数据报准备好的时候会返回给进程一个SIGIO信号,然后立即执行recvfrom系统调用,从内核中拷贝数据报到用户控件,拷贝完成之后返回拷贝成功提示,即可说明一个系统调用已经就绪。
这种模型的好处是,可以节省等待的时间或者多次询问的时间,直到数据报准备好之后,我们在回过头来处理,主循环可以继续进行。

异步IO模型

异步IO模型
通过调用aio_read(Posix异步IO函数以aio或者lio_开头),给内核传递描述符、缓冲区指针、缓冲区大小、文件偏移,并高数内核当整个操作完成时如何通知我们。如图所示,这个系统调用会立即返回,我们的进程也会阻塞等待IO操作完成。最大的特点是,通过内核通知我们IO操作何时完成。也就是说,等待内核数据报准备好,并且拷贝完成的时候,内核会主动给进程发送就绪信号,来告诉已就绪;

五种IO模型的比较

对于前四种IO模型是同步IO,最后一种是异步IO。何谓同步,简单理解来说,我们必须给内核发送recvfrom请求之后,才准备开始实现数据报从内核空间的拷贝,等到拷贝完成之后,内核空间会再给进程返回成功的信号。 异步IO,则是等待内核准备好之后,内核主动返回,而不需要进程主动调用recvfrom去向内核请求数据报。
总结,同步IO操作引起请求进程recvfrom阻塞,直到IO操作完成。异步IO操作不会引起进程阻塞。

猜你喜欢

转载自blog.csdn.net/ALITAAAA/article/details/109412312