1 简介

  网络IO模型有5种:阻塞IO、非阻塞IO、IO多路复用、信号驱动IO、异步IO

  本文仅对阻塞IO、非阻塞IO、IO多路复用进行讲解

  在网络通信中,对数据进行收发在发送端和接收端的相应设备上会进行如下顺序的传递:

  发送端应用的发送缓冲区->发送端操作系统的内核缓冲区->发送端网卡->网线->接收端网卡->接收端操作系统的内核缓冲区->接收端应用的接收缓冲区

  对数据进行写入时,应用程序调用write/sendto等相关系统调用将数据发送到接收端的接收缓冲区;在读取数据时,应用程序调用read/recvfrom等相关系统调用将数据从接收缓冲区搬运到用户区。

  以数据的读取为例,在调用read等系统调用时,会经历以下两个阶段:
 (1)等待数据到达内核接收缓冲区
 (2)将数据从接收缓冲区搬运到用户区

2 阻塞式IO

  阻塞式IO在进行数据读取时,如果内核中没有数据(发送端可能还没有发送数据或者发送的数据还没有达到),此时内核就开始等待数据,同时用户进程也进入阻塞状态,整个进程就会被挂起等待,不能做其他的事情。当有数据到达内核时,内核等待结束,将数据从内核拷贝到用户区,用户进程结束阻塞,从挂起状态转为运行状态。

  所以,阻塞式IO在进行数据读取时,上述两个阶段都会阻塞(内核等待数据,用户进程阻塞)。

  在Linux中,默认所有的socket都是阻塞式的。阻塞式接口是指当进行系统调用时,如果数据没有准备好,该应用进程就会被挂起,系统调用不会返回,直到有数据达到或者调用出错时,系统调用才会返回,进程才会结束阻塞状态。

  但是在网络编程中,一般服务器需要处理多客户端,如果是像这种单进程服务器。与一个客户端连接建立之后,服务器就会使用read等系统调用对客户端进行数据读取来处理请求。当该客户端没有发送数据或者发送的数据还没有达到时,服务器就会进入阻塞状态,此时整个服务器进程就会挂起。当其他客户端连接请求达到时,服务器由于处于挂起状态,什么也不能做,所以也不能对其他客户端进行处理。因此,这种单进程的阻塞式IO的服务器只能处理一个客户端的情况,这样的服务器没有任何的实用性。

  一种解决办法是,利用多进程或多线程来处理多客户端的情形。如果在对一个客户端进行读取时导致一个进程被挂起,可以创建其他的进程来处理其他客户端的请求。但是多进程和多线程的创建需要浪费一定的资源,当有过多的连接没有数据往来的时候,会造成浪费,同时也可能造成频繁的进程上下文切换。所以多线程做法一般适用于中小型应用场景。

3 非阻塞式IO

  非阻塞式IO在使用recvfrom等系统调用进行数据读取时,如果内核中没有数据到达,此时内核会进行等待。但是与阻塞式IO不同的是,此时的用户进程并不会被阻塞,不会被挂起,而是出错返回。

  但是之后内核将数据准备好之后,由于该系统调用已经返回,所以进程无法得到数据已经准备好并且无法将数据由内核拷贝到用户区。所以,此时还需要使用系统调用进行数据的拷贝。因为不知道内核什么时候将数据准备好,所以就需要不断的使用系统调用来询问内核有没有将数据准备好,一旦准备好就进行数据的拷贝。

  非阻塞式IO中,一般需要循环的对文件描述符进行读写,不断的询问数据有没有准备好。这个过程就称为轮询。因此,在非阻塞IO中,内核在等待数据,用户进程在轮询访问数据有无准备好。

  在该模型中,进程大部分的工作都是在轮询访问,如果大多数连接都没有数据到达,那么大多数轮询都是空轮旋,并没有发挥实际有效的作用,所以这样做实际是对CPU资源的一种浪费。一般在特定场景下才会使用该模型。

4 IO多路复用

  既然非阻塞IO中,进程会产生很多空轮询,那能不能直接操作系统告诉我们那个连接的数据准备好了,我们直接去轮询这些连接不就好了?IO多路复用就是做这一件事情

  IO多路复用下,进程首先使用select/epoll等系统调用等待多个连接。select等系统调用可以设置阻塞和非阻塞(或者阻塞的时间)。如果是阻塞方式,若等待的所有连接的数据均未达到,此时进程会阻塞在select处。当至少有一个连接就绪条件满足时,该系统调用就会返回,然后应用进程再调用read等分别对就绪的连接进行数据的拷贝。如果是非阻塞方式或者设置了阻塞的时间,当没有调用select时或者在规定时间内没有连接满足就绪条件,此时select会出错返回-1,此时为了对数据进行操作,所以必须循环的调用select来判断有无连接满足就绪条件。

  当等待的多个连接中至少有一个满足就绪条件时,select返回数据准备好的连接。此时应用进程调用read(此时的套接字是阻塞的)等对数据进行拷贝。此时,read一定不会阻塞。因为内核中一定有数据到达。

  所以,通过上述的说明,对于单进程的服务器可以通过IO多路复用的方式来处理多客户端的情况。此时便可避免多线程阻塞IO带来的多进程或多线程的创建造成的资源方面的问题,同时可以处理多客户端。但是两种方式各有优缺点,比如在连接比较少的时候,内核这种处理显得太笨重。

5 总结

5.1 阻塞IO和非阻塞IO

5.1.1 共同点

  数据从内核拷贝到应用进程其实还是阻塞的状态

5.1.2 不同点

  阻塞IO需要一直等待内核数据准备好,进程处于阻塞状态;非阻塞IO一直在询问内核数据是否准备好,进程处于运行态,一直占用着CPU

5.2 非阻塞IO和IO多路复用

5.1.1 共同点

  数据从内核拷贝到应用进程其实还是阻塞的状态

5.1.2 不同点

  当有多个连接的时候,非阻塞IO会不断地询问每个连接的数据是否准备好,如果准备好则调用read系统调用进行读取,但是我们上面说过,如果连接一直没有数据到,将会有许多无用的轮旋;IO多路复用则把这项工作交给操作系统,有操作系统通过与IO设备绑定的回调直接把有数据到来的连接返回给应用进程,应用进程可以直接一个个读取而无需再像非阻塞IO那样去询问没有数据的连接。

6 结尾

  在网络刚刚诞生的时代,服务器还没有这么大的负载,用单线程阻塞IO的时候搓搓有余。

  随着并发量越来越大,单线程无法支撑,人们便利用多核并发处理能力,每个连接创建一个线程进行处理,也就是多线程阻塞IO

  但是慢慢发现,创建过多线程造成很大地资源浪费,并且频繁地上下文切换也带来不菲地系统开销,因此出现了非阻塞IO(单线程多线程根据具体业务要求),线程每次询问操作系统是否准备好数据时不再向阻塞IO那样,要把自己挂起,而是每次询问,操作系统直接返回结果,有数据就返回数据,没有数据就返回异常,但同时造成大量地空沦陷,不是所有的连接都有数据到来,进程也会一直占用CPU。

  因此,人们后来又发明了IO多路复用,将“轮旋”操作交给操作系统完成,操作系统通过与IO设备的回调等优化,直接返回数据准备好的连接给应用进程。典型的实现有windows的select和linux的epoll。window的select虽然也是一个个轮询每一个连接,但是每次轮询都是在内核空间下进行,不存在用户态和内核态之间的切换,相比非阻塞IO每次询问都是一次昂贵的系统调用。而在linux系统上实现的epoll则进一步优化(通过红黑树),使得可以在O(1)的时间复杂度内返回数据准备好的连接,而不需要轮询。

  再后来出现的信号驱动IO和异步IO也是为了进一步解决应用场景而出现的技术,本文不再展开,有兴趣的读者可以自行查阅,一般的业务场景最多就用到IO多路复用技术。技术没有好坏,仅仅只是为了适应应用场景而被创造出来,选用什么技术也要看具体的业务场景。

6 参考

计算机网络------五种IO模型
浅谈5种IO模型——阻塞式IO、非阻塞式IO、信号驱动IO、多路复用IO及异步IO
图解 | 原来这就是 IO 多路复用
四图,读懂 BIO、NIO、AIO、多路复用 IO 的区别

计算机网络——阻塞IO、非阻塞IO、IO多路复用相关推荐

  1. IO模型(阻塞,非阻塞,多路复用)

    在了解IO模型前,先了解什么叫IO,IO得操作是怎么样的? IO既输入输出,指的是一切操作程序或设备与计算机之间发生的数据传输的过程.它分为IO设备和IO接口两个部分. IO设备:就是指可以与计算机进 ...

  2. 什么是IO多路复用_IO多路复用同步异步阻塞和非阻塞

    转自:http://www.elecfans.com/baike/wangluo/fuyongqi/20180307644141.html 一.什么是socket? 我们都知道unix(like)世界 ...

  3. IO模型_阻塞_非阻塞_多路复用

    在了解IO模型前,先了解什么叫IO,IO得操作是怎么样的? IO既输入输出,指的是一切操作程序或设备与计算机之间发生的数据传输的过程.它分为IO设备和IO接口两个部分. IO设备:就是指可以与计算机进 ...

  4. 阻塞IO 非阻塞IO IO多路复用 异步IO 区别

    Linux中五种IO模型:阻塞IO模型.非阻塞IO模型.IO复用模型.信号驱动IO模型.异步IO模型 linux的内核将所有外部设备都看作一个文件来操作,针对一个文件的读写会调用内核提供的系统命令,返 ...

  5. python gevent模块 下载_Python协程阻塞IO非阻塞IO同步IO异步IO

    Python-协程-阻塞IO-非阻塞IO-同步IO-异步IO 一.协程 协程又称为微线程 CPU 是无法识别协程的,只能识别是线程,协程是由开发人员自己控制的.协程可以在单线程下实现并发的效果(实际计 ...

  6. IO:同步,异步,阻塞,非阻塞

    IO - 同步,异步,阻塞,非阻塞 都是老生常谈的东西,多通读几遍,理解透彻! 实际上同步与异步是针对应用程序与内核的交互而言的.同步过程中进程触发IO操作并等待(也就是我们说的阻塞)或者轮询的去查看 ...

  7. Linux IO - 同步,异步,阻塞,非阻塞

    From:http://blog.csdn.net/historyasamirror/article/details/5778378 同步/异步,阻塞/非阻塞概念深度解析:http://blog.cs ...

  8. 网络IO之阻塞、非阻塞、同步、异步总结

    1.前言 在网络编程中,阻塞.非阻塞.同步.异步经常被提到.unix网络编程第一卷第六章专门讨论五种不同的IO模型,Stevens讲的非常详细,我记得去年看第一遍时候,似懂非懂,没有深入理解.网上有详 ...

  9. 阻塞和非阻塞、同步和异步 、五种IO模型

    阻塞和非阻塞,同步和异步 1 例子 故事:老王烧开水. 出场人物:老张,水壶两把(普通水壶,简称水壶:会响的水壶,简称响水壶). 老王想了想,有好几种等待方式 1.老王用水壶煮水,并且站在那里,不管水 ...

  10. 阻塞IO, 非阻塞IO, 同步IO,异步IO

    阻塞IO, 非阻塞IO, 同步IO,异步IO 介绍 先说明几个概念 用户空间与内核空间 为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操心系统将虚拟空间(内存)划分为两部分,一部分 ...

最新文章

  1. PDF文字怎么编辑,PDF文档编辑方法
  2. 目标检测的常用数据处理方法!
  3. 今天看到一个很个性的blog
  4. 在浏览器中输入URL按下回车键后发生了什么
  5. vscode中添加C++编译
  6. 基于CentOS 搭建 Seafile 专属网盘
  7. Tkinter的Radiobutton组件
  8. Pygame - Python游戏编程入门(1)
  9. Spring Cloud是什么,和Dubbo对比呢?
  10. css flexbox模型_Flexbox和CSS Grid之间的主要区别
  11. 机器学习接口和代码之 线性回归
  12. 苹果断开电脑连接服务器无响应,mac电脑iTerm2链接linux服务器断线解决方案
  13. phpstudy的php fpm,PHP_php-fpm配置详解,php5.3自带php-fpm复制代码 代码 - phpStudy
  14. hrbust/哈理工oj 1787 New Fibonacci Number【欧拉降幂+矩阵快速幂】
  15. 5个小众视频素材网站,你知道吗?
  16. VNC远程控制软件,五大容易上手的VNC远程控制软件
  17. 免费edu邮箱申请注册地址
  18. redis分布式锁的安全性及与zookeeper的对比
  19. Python学多久能接单赚钱?按照这套路线学习,30天内就可以!
  20. 【JavaScript】浏览器

热门文章

  1. linux ntp 定时同步_linux ntp时间同步
  2. Karate网络数据的权重部分导入(networkx)
  3. 虚拟服务器+解释,螃蟹每日推特:关于虚拟服务器的相关解释
  4. HashMap面试,看这一篇就够了
  5. pyinstaller打包文件及warn文件中许多missing module 的解决方法
  6. 2022-2027年中国茶色素市场规模现状及投资规划建议报告
  7. oracle 优化之parallel和append
  8. :focus-visible 聚焦问题
  9. SAP中批量用户账户锁定操作
  10. ### java8之collector详解,以及结合toMap,sorted,groupingBy使用例子