Linux中的网络I/O模型

Linux中的网络I/O模型

​ 网络的I/O一直是制约程序运行的关键,无论是C、C++还是Java都有自己I/O模型的实现,所有高级语言中的I/O模型,都脱离不了底层操作系统对于I/O的支持,在Windows中或者Linux中都有各自对于I/O的实现,在《Netty权威指南》中也有对Linux的I/O模型的简述,本文主要参考此书对Linux中I/O模型作简要分析描述。

一、同步、异步和堵塞、非堵塞

想要理解同步、异步、堵塞和非堵塞的区别首先要理解网络I/O的过程,一般针对网络I/O的操作,可以分成两个阶段,准备阶段和操作阶段。

  • 准备阶段是判断是否能够操作(即等待数据准备就绪),在内核进程完成的。
  • 操作阶段则执行实际的I/O调用,数据从内核缓冲区拷贝到用户进程缓冲区。

1.同步和异步

同步和异步描述的是用户进程和内核进程的交互方式,它描述的是I/O操作两个阶段的整体行为。

  • 同步是指用户发起I/O请求以后堵塞当前进程,等待或者轮询内核进程的I/O完成后才执行后续操作
  • 异步是指用户发起I/O请求以后可以继续执行后续操作,当内核进程完成I/O操作,并将数据拷贝到用户缓冲区以后通过回调函数通知用户进程。

2. 堵塞和非堵塞

堵塞和非堵塞描述的是用户进程调用内核 I/O 操作的方式,它描述的是网络I/O操作的第一阶段的行为。

  • 阻塞是指 I/O操作的准备阶段需要一直等待数据准备就绪,当内核没有将数据准备好的时候,需要堵塞住当前进程(用户进程挂起)。
  • 非堵塞是指I/O操作的准备阶段发起系统调用以后可以执行后续流程,不需要堵塞住等待数据完成(用户进程轮询或注册回调函数)。

二、堵塞型I/O模型

image-20220807195631468

​ 这是最为常用的I/O模型,在Java的1.4版本之前只支持该类型的I/O,当用户进程发起I/O操作时,如果DMA未将数据复制到内核空间(数据未准备好),那么用户进程将会挂起堵塞住,无法继续执行,直到数据准备完成,用户进程将数据从内核空间复制到用户空间,致词I/O操作最终完成。

三、非堵塞型I/O模型

image-20220807204217690

​ 此I/O模型在数据未准备好之前不会进行挂起等待,而是内核返回一个错误(EWOULDBLOCK),当用户进程收到错误后不断轮询内核进程,直到数据准备好用户进程开始将数据从内核空间复制到用户空间,完成I/O操作。用户进程持续轮询内核进程,以查看某个操作是否就绪。这么做往往需要消耗大量的CPU时间。所以在多数情况下,高级语言层面一般不会采用该模型实现I/O操作。

四、I/O多路复用模型

image-20220807204249797

​ 在此模型中,可以看到操作系统将I/O操作的两个阶段进行了更加明显的划分,在第一阶段操作系统提供了select/poll/epoll等系统调用,让多个用户进程堵塞在这些系统调用上,而并非堵塞在真正的I/O系统调用上。进程将一个或者多个fd(文件描述符)传递给select/poll/epoll等系统调用,当有fd就绪时,立刻回调函数rollback,通过调用真正的I/O系统调用(recvfrom)将数据从内核空间复制到用户空间。在链接数较少的情况下,该模型并不适用,因为我们此时多了一个系统调用,使用该模型的优势在于我们可以等待多个描述符就绪。

与I/O多路复用密切相关的另外一种I/O模型是在多线程中使用堵塞型I/O。这种模型与多路复用极为相似,但它没有使用select堵塞在多个文件描述符上,而是使用多个线程(每个文件描述符一个线程),这个每个线程都可以自由地调用诸如recvfrom之类的堵塞式I/O系统调用了。

摘自《UNIX网络编程卷1:套接字联网API(第3版)》

五、信号驱动型I/O模型

image-20220807204313016

​ 通过sigaction系统调用安装一个信号处理函数,当发起调用以后立刻返回,当有fd准备就绪时内核发送SIGIO信号通知用户进程,用户进程通过recvfrom进行数据复制,最后处理数据。这种模型的优势在于等待数据报到达期间进程不被堵塞,主循环可以继续执行,只要等待来自信号处理函数的通知即可。

六、异步I/O模型

image-2022080720438886

​ 此模型通过aio_read系统调用告知内核启动I/O操作,告知以后用户进程可以继续执行后续操作,内核完成I/O的整个操作(包括将数据从内核空间复制到用户空间)之后,通过信号告知用户进程I/O操作完成,用户进程执行对数据的处理。此模型下,整个I/O操作的两阶段都是由内核进程完成,用户进程只需要进行系统调用之后等待完成信号即可。

总结:

对于这几种I/O模型,生活中其实存在很多例子,我们以去售票窗口买车票为例,说明这几种I/O模型的区别。

  • 堵塞型I/O:到窗口去买票,如果此时没有票,你一直等在窗口前(堵塞),直到该窗口有车票准备好,你从窗口取票离开。
  • 非堵塞型I/O:如果窗口没有票,你就去做别的事情,你每隔一段时间来看一下有没有票(轮询),直到有票你取票离开。
  • 多路复用型I/O:买票的时候由专人负责维护所有排队买票的人,并且收集每个人的买票需求,当窗口有票的时候,专人负责通知需要车票的人去窗口取票。
  • 信号驱动型I/O:买票的时候如果窗口没票,你可以回家等着或者去干别的事情,当有票到达窗口的时候,售票员打电话通知你过来取票。
  • 异步I/O模型:买票时你只需要告诉售票员你的需求,并且把你家的地址告知她,之后你可以去做其他事情,当窗口有票的时候,售票员负责将车票送到你家,你根本不需要关心车票什么时候有,你只需要在家等待即可。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值