在Linux平台下的服务器开发中,如何去构建高性能的网络通信框架是重中之重,自然就绕不开网络通信模型的选择和应用;目前网络通信模型中涉及到的模式有两个:Reactor模式和Proactor模式。
在介绍这两个模式之前,先详细地阐述下阻塞IO、非阻塞IO、同步、异步的概念,因为经常有很多同学能把这些词汇编出各种奇怪的组合出来,连自己都不知道是什么意思。
阻塞IO:当应用层发起read请求时,发出read请求的线程会被挂起,直到操作系统完成数据从内核区到应用层缓冲区的拷贝,read调用才返回;write操作也是一样。
非阻塞IO:当应用层发起read请求,而操作系统没有准备好数据,read调用会立刻返回;同时操作系统会返回一个EWOULDBLOCK的错误码。但发起read请求的线程会不断地去询问操作系统“数据准备好了吗?”,如果准备好了,那么就把数据从内核空间拷贝到应用层缓冲区。
上面就是阻塞IO和非阻塞IO,但是有一点需要说明,在操作系统把数据准备好,并把数据拷贝出来的过程是同步的,也就是说必须要拷贝完,read才会返回。所以同步/异步是用于形容数据从内核空间拷贝到应用程序缓冲区的过程。
同步:当操作系统内核准备好数据,应用程序发出read请求,数据的拷贝是和read函数同步进行的,如果数据较多,那么read调用的耗时会较长。
异步:当应用程序发出***aio_read***请求后,无论操作系统是否把数据准备好都会立即返回,操作系统自主把数据从内核空间拷贝到应用程序的缓冲区来,而后通知应用程序,数据已经拷贝完成;无需应用程序等待或者以轮询的方式去查看数据是否拷贝完成。
介绍完上述基本概念和思想,那么我们结合书店买书的场景发散性地思考一下:
阻塞IO:去书店问老板要具体某一本书,老板翻箱倒柜地寻找,你就一直在那里等,直到老板找到为止。
非阻塞IO:你觉得第一种方式太笨了,去书店问老板要某本书,老板拼命地找,你可以去喝喝咖啡或者上街看看美女,过一阵子再问老板:“老板,书找到了吗?”。
非阻塞IO+多路复用技术:后来觉得总是去问老板“书有没有找到”太费事了,你叫老板通知你,书找到了,你就去拿。老板通知你这件事就相当于操作系统的IO复用技术(select、poll、epoll)。
上述三种情况中,我们去拿书的时候便是***同步***的,也就是老板给我们书,肯定是一次性给完,不可能给一本,你出去一下,再回来取第二本。
异步:相当于现在的网购,在网上写好地址,写好书名,付好钱,老板那里有书了,直接寄给你,等你收到通知时,书已经邮寄到你家里了。
windows中IOCP模型就是异步思想的最好体现,操作系统帮我们完成数据的收发,我们只需对数据进行加工便可;目前我所在公司开发的摄像头组件服务器便是采用IOCP模型,同时接收几千台设备上报的报警信息都没问题。
那么现在我们应该清楚了,Linux平台下,无论是采用哪种IO复用技术都是同步调用,也就是***IO复用机制+同步调用+非阻塞***模型。或者***IO复用机制+同步调用+阻塞***模型。没有其他的组合,在Linux平台下,基于socket的异步IO调用,在性能上还是有待考究的,目前只实现了磁盘的异步IO。
介绍完这些基本概念,现在逐步剥开Reactor和proactor模式的面纱。在Linux平台下,基于epoll模型的事件通知机制,当socket上有读写事件发生时,便通知应用程序发出read/write操作,其他时间应用程序可以去做其他事情,这种模型便是Reactor模式。换句话说,Reactor模式是基于待完成的socket IO事件,需要应用程序自己去处理的。
Proactor模型:采用IO多路复用技术,比如:IOCP模型。唯一不同的是应用程序无需发出read/write请求,当得到事件通知时,操作系统已经把数据读取到应用层缓冲区或者将应用层数据拷贝内核空间,完成数据的发送。应用程序只需准备装数据的容器和待发送的数据。那么Proactor模式也就可以理解为:IO复用机制+异步调用,这里就没有所谓的阻塞和非阻塞的概念了。
来源:oschina
链接:https://my.oschina.net/u/4264465/blog/4503325