IO复用 & UNIX下的五种IO模型

2014-10-28 23:43:13   最后更新: 2015-02-16 16:33:33   访问数量:1661




考虑一个简单的客户端程序:从标准输入读取数据(fgets),然后发送给服务器,并接收服务器返回的TCP套接字

如果当客户端进程阻塞在从标准输入读取数据期间,服务器进程被杀死,那么服务器进程会给客户端发送一个 FIN,但是客户端需要在阻塞结束后才可以接收到这个FIN

因此,我们需要一种预先告知内核的能力,使得内核一旦发现进程指定的一个或多个IO条件就绪就去通知进程,这个能力就称为IO复用

 

  • IO复用使用在以下场合:

  1. 当客户处理多个描述符时(如上面所说的例子,同时使用交互式输入和网络套接字),必须使用IO复用
  2. 一个客户端程序同时处理多个套接字,虽然这样的情况是比较少见的
  3. 如果一个TCP服务器既要处理监听套接字,又要处理已连接套接字,一般需要使用IO复用
  4. 如果一个服务器需要处理多个服务或者多个协议,一般需要使用IO复用

 

当然,IO复用并非只限于网络编程

 

 

下面介绍五种 IO 模型:

  • 阻塞式IO
  • 非阻塞式IO
  • IO复用(select 和 poll)
  • 信号驱动式IO(SIGIO)
  • 异步IO(POSIX的aio_系列函数)

1、阻塞式IO模型

阻塞式IO模型是最常用的IO模型

默认情况下,所有套接字都是阻塞的,如下图所示:

 

这样的IO模型中,系统调用会从应用进程空间切换到内核空间中运行一段时间后再切换回来

只有当数据报到达并且被复制到应用进程缓冲区中或者发生错误才返回,最常见的错误返回是被信号中断

2、非阻塞式IO模型

非阻塞式IO并不让进程睡眠,而是在数据报没有准备好的时候由内核立刻返回一个错误

当一个进程循环调用非阻塞式IO等待数据报时,我们称之为“轮询”

这样做会耗费大量的CPU时间,通常只在专门提供某一功能的系统中才会用到

 

3、IO复用模型

IO复用的系统调用有select和poll

系统阻塞在这两个系统调用上,而不是阻塞在真正的IO系统调用上

select 调用等待数据报套接字变为可读,然后调用真正的IO系统调用去进行IO操作,将所读的数据写入应用程序缓冲区中

使用 IO 复用模型的好处在于可以同时等待多个描述符就绪,甚至可以实现复杂的等待条件

 

等待多个描述符的另一种实现是创建多个线程,每个线程使用一个阻塞式IO系统调用去等待一个描述符

 

4、信号驱动式IO模型

我们也可以设定 SIGIO 信号的信号处理方式,然后让内核在描述符就绪时发送 SIGIO 信号通知我们

这种方式就是信号驱动式IO

信号驱动式IO模型的优势在于等待数据报到达期间进程不必被阻塞,一旦数据报准备好,可以立即进行处理

 

5、异步IO模型

aio_开头的一些列系统调用实现了异步IO模型

这些函数的工作机制是:告知内核启动某个操作,并让内核在整个操作完全进行完成之后通知进程

信号驱动式IO是在IO操作进行之前通知进程进行相应的操作,而与此不同,异步IO模型让内核完成全部的缓冲区复制工作,直到全部工作完成才去通知进程(比如产生某个信号)

 

 

 






读书笔记      技术帖      linux      unix      网络      network      c语言      unp      unix网络编程      tcp      udp      龙潭书斋      io      select      epoll      poll     


1#jeffei: (回复)2016-06-10 00:00:04

1.在非阻塞式IO模型中,应用进程需要不断的轮询,那么,在轮询期间,应用进程可不可以去执行其他任务? 2.阻塞式IO和IO多路复用的区别是后者阻塞在系统调用上(select,poll,epoll),那么,相比于阻塞在具体IO调用上,IO多路复用模型有何优势? 小弟初学,提问水平一般,望大神见谅。

2#博主: (回复)2016-06-11 14:17:15

回复:1#1. 非阻塞IO会在读写不就绪的情况下立即返回错误,如果需要在一段时间后再次尝试是否就绪,这就是轮询的机制,具体以什么频率轮询,轮询期间做什么,是你的业务逻辑自己决定的 2. IO复用模型的优势在于可以同时等待多个未就绪的 fd,而阻塞IO、非阻塞IO的每次调用都只能针对一个 fd 进行等待或轮询

3#jeffei: (回复)2016-06-11 22:34:23

回复:2#非常感谢博主的指点。 关于IO复用,看了博主的回复,我现在理解相对清晰。对于阻塞式IO和非阻塞式IO,我的理解是这样的,博主你看看这样理解可以吗? 对于阻塞式IO,在读写不就绪的情况下,应用进程会被挂起,直到读写就绪,进程被唤醒,返回结果,然后接着往下执行。在这个过程中,当前应用进程不能去操作别的fd。 对于非阻塞式IO,在读写不就绪的情况下,内核应用进程返回一个错误,那么,应用进程这个时候可以去执行其他fd的操作,只是每过一段时间都会来轮询一下当前fd是否就绪。 以上理解不知到位否?

4#博主: (回复)2016-06-12 13:43:58

回复:3#是这样的,非阻塞IO在不就绪的时候会立即返回,阻塞IO会等待就绪,非阻塞IO返回后你是否需要轮询是你的业务逻辑自己考虑的事了

京ICP备15018585号