Linux里五种I/O模型

阻塞I/O

如上图,我们写的应用程序使用数据流(UDP)Socket接收数据,调用recvfrom()系统函数接收网卡上的数据。在阻塞I/O下,调用recvfrom()将造成进程阻塞,直到数据接收完毕。

内存空间有系统空间和用户空间,并且都有相应的缓冲区:

  • 第一阶段(wait for data等待数据准备):进程阻塞,内核接管,复制数据到系统空间里的数据缓冲区(当然是能够从网卡上接收到数据)。接收完毕后,则数据准备完毕(datagram ready)。
  • 第二阶段(copy data from kernel to user从内核拷贝数据到用户缓冲区):这时候进程仍然阻塞,内核将系统空间内缓冲区ready的数据复制到用户空间里的用户自己定义的缓冲区。拷贝完毕则唤醒进程。 整个阶段,进程都是阻塞的,直到数据读取到用户缓冲区内。

非阻塞I/O

如上图,同样应用程序调用数据流(UDP)Socket接收数据,调用recvfrom()系统函数,并且设置了Socket为non-blocking非阻塞。

这时我们调用系统函数recvfrom()则不阻塞进程,如果数据没有在系统空间的缓冲区内准备好,则立即返回一个error,直接得到一个结果,这时候进程可以做点其他任务而不用阻塞在这里。但是如果数据在系统空间内的缓冲区准备好了,则将开始从系统空间拷贝数据到用户空间。

I/O 多路复用(IO multiplexing)

I/O多路复用大致情况如上图。I/O多路复用也就是我们常说的select、poll以及epoll,它能够使一个进程能够同时处理更多的连接。

这里就以select为例:select()也是一个系统调用,如果一个进程调用了select()那么这个进程也会被阻塞。

  • 第一阶段:应用程序进程调用select(),这时该进程阻塞,不过内核会监视应用程序向select注册的所有Socket。如果注册的Socket中有数据以及在系统空间缓冲区里准备好了的,则该进程被唤醒。
  • 第二阶段:从select()的阻塞中返回,应用程序进程只能知道向select注册的Socket里有数据准备好的Socket,但是并不知道具体是哪个Socket数据准备好了。所以,应用程序需要自己遍历Socket,找出数据准备好的Socket,然后调用recvfrom()函数将系统空间缓冲区内数据复制到用户空间缓冲区内。

信号驱动 I/O(signal driven IO)

Linux内核定义了很多信号,如SIGUSR1和SIGUSR2都是可以用户自定义发送/处理的信号。

应用程序首先需要安装信号处理器(即提供一个回调函数给内核),当相应事件发生的时候,操作系统会激活该信号,处理权交给进程,由进程调用处理该信号的回调函数。

在信号驱动I/O中,应用程序先安装信号处理器,返回结果,进程可以继续执行。当数据在系统空间内准备好了后,内核会激活信号,进程则会调用相应的回调函数(这里数据准备好了则直接调用recvfrom()函数),然后数据则直接拷贝到用户空间缓冲区内。

异步 I/O(asynchronous IO)

异步I/O则是调用aio_read()系统函数,传入了用户空间缓冲区的地址指针。调用后进程不会被阻塞,则可以做其他事情,内核会在将数据复制到系统空间缓冲区,然后再将数据复制到用户提供的用户缓冲区地址中。都做完了后,则内核发送一个signal通知应用程序read完成了。这时应用程序之前提供的回调函数,由该进程来执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值