概述本文从I/O网络模型出发,介绍了目前主流的几种网络模型,然后讨论了同步阻塞I/O、同步非阻塞I/O、I/O多路复用。详细解释了机制和过程,最后通过生活中的一个例子加深了对这3种网络模型机制的理解。I/O操作网络IO的本质是对socket的读取。Sockets在Linux中被抽象为流,IO操作可以理解为对流的操作。为了操作系统的安全,进程不能直接操作I/O设备。它必须通过系统调用请求内核协助完成I/O动作,内核会为每个I/O设备维护一个缓冲区。整个请求过程可以概括为:用户进程发起请求,内核收到请求后,从I/O设备中获取数据放入缓冲区,然后将缓冲区中的数据复制到地址空间用户进程,用户进程获取到数据,然后响应给客户端。如下图所示:在整个请求过程中,数据从IO设备输入到内核缓冲区需要时间,从内核缓冲区复制到用户进程也需要时间(从IO设备到用户进程需要时间更多)IO设备到内核比从内核到进程)。因此,根据这两个时期等待方式的不同,I/O动作可以分为以下五种模式:阻塞式I/O(阻塞式I/O)非阻塞式I/O(非阻塞式I/O)I/O输出多路复用(I/OMultiplexing)信号驱动I/O(SignalDrivenI/O)异步I/O(AsynchronousI/O)这里为了更好的理解I/O多路复用,前三类I/OO网络模型同步阻塞I/O同步阻塞I/O流程图如下:当用户进程调用recv()/recvfrom()系统调用时,内核开始IO的第一阶段:准备数据(用于网络IO例如很多时候一开始数据还没有到达,比如一个完整的UDP包还没有收到,这时候内核要等待足够的数据到达)。这个过程需要等待,也就是说数据复制到操作系统内核的缓冲区需要一个过程。在用户进程端,整个进程都会被阻塞(当然是进程自己选择阻塞)。第二阶段:当内核等待数据准备好后,会将内核中的数据拷贝到用户内存中,然后内核返回结果,用户进程释放block状态,重新开始运行。所以,同步阻塞(blockingIO)的特点是在IO执行的两个阶段都被阻塞。同步非阻塞I/O同步非阻塞I/O的流程图如下:非阻塞IO也会执行recvform系统调用来检查数据是否就绪。非阻塞recvform系统调用后,进程不阻塞,内核立即返回进程。如果数据没有准备好,此时会返回错误。进程返回后,可以做其他事情,然后发起recvform系统调用。重复上述过程,反复进行recvform系统调用。此过程通常称为轮询。轮询检查内核数据,直到数据准备好,然后将数据复制到进程进行数据处理。需要注意的是,在复制数据的整个过程中,进程仍然处于阻塞状态。所以同步阻塞(nonblockingIO)的特点是在IO执行第一阶段不阻塞,第二阶段阻塞。I/O多路复用I/O多路复用的基本原理是:select/epoll函数会不断轮询所有负责的socket,当某个socket有数据时通知用户进程。单个进程可以同时处理多个网络连接的IO。当用户进程调用select时,整个进程会被阻塞。同时,内核会“监控”所有负责select的socket。当任何套接字中的数据准备就绪时,select将返回。这时用户进程调用read操作将数据从内核拷贝到用户进程。I/O多路复用的流程图如下:I/O多路复用类似于阻塞式I/O,不同的是这里使用了两次系统调用(select和recvfrom),而阻塞式IO只调用一次系统调用(recvfrom).I/O多路复用用户进程阻塞的不是recvfrom,而是select/epoll。但是,使用select的好处是它可以同时处理多个连接。(select/epoll的详细原理可以参考大话Select,Poll,Epoll)因此,如果处理的连接数不是很高,使用select/epoll的webserver不一定比使用multi的webserver好-threading+blockingIO嗯,可能延迟更大。select/epoll的优势不在于处理单个连接速度快,而在于可以处理更多的连接。场景示例为了更好的理解以上三种I/O模型,我们举一个生活中的例子。前段时间踢球扭伤了膝盖,需要去医院做个核磁共振,然后让专家看看恢复情况如何。我们以此为例进行说明。首先对齐几个概念Patient:作为用户进程Expert:作为内核进程MRIfilm:I/Orequests中的数据Hospital:作为操作系统,可以派遣expert处理patientrequests兄弟们都知道拍片通常需要3working几天出来。然后片子出来后,去医院拿片子,再看专科医生。一般情况下,专科医生处理一个病人需要10-20分钟。I/O操作的两个阶段对比,等待数据接收<-->等待电影出来,从内核copy数据到用户态<-->拍完电影再咨询专家。那你可以把看病看成是数据处理。有了以上的概念,我们再来看看三款I/O模型的情况(为了更好的说明,我们将拍摄时间缩短了1小时)。同步阻塞I/O患者去医院找专家,然后拍MRI,然后等待。这个时候,这位专家已经不能处理其他患者的请求了。医院要想收更多的病人,就得找更多的专家。这时候对于医院来说,一个专家救治一个病人需要1小时+10分钟。对于患者来说,在这一个小时之内,他们只能傻傻地等待,不能做其他事情。同步非阻塞I/O和同步阻塞I/O的区别在于患者拍完片可以马上回去,不用在医院等一个小时。此时,对于患者来说,在这1小时内可以做其他事情,但患者必须每隔一段时间询问专家片子是否准备好(因为片子随时都可能准备好,严格来说不是1小时)。这类似于轮询机制。所以,同步非阻塞I/O机制的好处是耐心,理解这个机制主要还是从应用程序的角度。以上两种I/O复用的场景,如果医院想要接收更多的病人,只能增加专家的数量。当患者数量较少时,此模型很好。然而,当患者数量不断增加时,医院的处理能力却跟不上。这时候,医院想出了一个机制:把核磁共振成像单独拿出来,让专门的医生处理(简称拍片医生)。每个病人拍完片子都会记录下来,片子医生会定期检查哪个病人的片子出来了(selectpolling)/医院建立了erp系统。一旦有病人的片子出来,拍片的医生就会得到通知。同时通知相应的患者(epoll)。从医院的角度来看,在这样的机制下,一个专家+一个放射技师可以处理多个病人(拍片的时间远远少于出片的时间)。当然,为了做更大的规模,医院还是可以招募更多的专家。多线程和IO多路复用不冲突。因此,上述机制的一个核心思想就是将集中式(central)处理变为分散式(distributed)处理。原来是一个专家负责拍片+诊断,现在变成了拍片医生+诊断专家,剥离了耗时的I/O等待,实现了高吞吐。参考文档https://blog.csdn.net/historyasamirror/article/details/5778378https://blog.csdn.net/zhougb3/article/details/79792089https://www.cnblogs.com/654321cc/p/7688351。htmlhttps://tech.meituan.com/2016/11/04/nio.htmlhttps://www.jianshu.com/p/76ff17bc6dea
