ace将网络编程进行了模式化,以便你不必每次都重复相同的代码。
网络编程需要处理的事情多括中断,并发,多线程等,程序格式相对固定,但是健壮的网络程序则相对复杂。为了处理这些情形,ace内建了几个网络编程的模式。
最基本的模式当然是直接使用sock进行单客户单服务器单线程的一对一模型,这种模式相对简单,也和ace关系不大,但是这样编写的程序不能处理并发的情况,可用性很差或者说基本不具有可用性。
最简单的处理并发但是却使用单线程的框架在ace中称为reactor框架,在这种框架下,reactor扮演了协调员的角色,应用程序编制者需要首先写好各种各样的事件处理程序,然后在reactor中进行登记,reactor以阻塞的方式同时监视所有可能发生的事件,并且在相应的事件发生的时候调用对应的处理过程。这种框架解决了在单线程的前提下解决了并发,但是存在一定的问题,如果某个事件执行过程过长,则可能导致reactor漏过某些事件。
另外一种单线程处理并发的模式称为异步i/o的proactor模式,这种模式和前面介绍的reactor模式其实区别不大,唯一的区别之处在于,server类在对从网络上收到的消息进行处理的时候,后者并不直接让处理器处理收到的消息,而是首先将消息转换为一个消息块结构(ace_message_block,通过this->reader_.read函数),然后再让相应的处理函数处理已经接收好的消息块结构。
比较一下reactor框架和proactor框架,前者的执行流程是: 监视事件->调用事件处理过程->继续监视事件。 后者的执行流程是: 监视事件->产生消息->处理消息->释放消息->继续监视事件。这两种不同的框架在引入各自的多线程概念以后,就衍生出不同的多线程框架。
前面说过,使用多线程进行网络编程也有两种框架,半同步/半异步框架和领导者/跟随者框架。前者对应的是proactor框架,后者对应的是reactor框架。所谓半同步或者半异步框架,执行的流程是:主线程负责 监视事件->产生消息->放入消息队列->监视事件,工作线程则负责从获取消息->处理消息->从消息队列获取另外一个消息。 这种框架的优势在于,由于构造消息并且将其放入消息队列的时间是可以控制的,因此,可以很好的处理网络峰值的情况,即使出现很高的峰值,也不会造成消息的遗漏,但是由于消息存在一个入队列,出队列的过程,因此性能相较另外一种模型,理论上更差。
后者则是一种相对更复杂的模型,在线程池中只有一个线程是领导者线程,其他为跟随者线程,领导者线程监视事件,在事情发生的时候,首先寻找另外一个线程变为领导者,然后自己再处理事件,处理完成以后,首先尝试再次成为领导者,如果尝试失败(另外一个线程已经成为领导者),则自己变成跟随者。 这种模型基于reactor模型,没有消息队列的概念,由于不存在出入队列的过程,性能相对前者理论上更好。但是如果存在很高的网络蜂拥,则可能由于所有的线程都在处理各自的事件,导致没有领导者可用,出现数据丢失的可能。
在这两种多线程模型中都存在线程池的使用。在半同步/半异步模型中,工作者线程可能为一个工作者线程池。消息队列的线程同步的工作已经由ace框架自动完成。
对于领导者/跟随者模型中,必然存在一个对等的线程池,线程池的数目取决于系统能够承受的数目,单就对于模型本身来说,线程池的线程数目越大,能够承受的网络蜂拥的极限值也越大。 但是如果执行每个请求的时间都很短,则系统中存在大量永远也用不到的线程,浪费了系统的资源。
如果使用多处理器的系统,应用程序必然能够从多线程(工作线程和跟随者线程)结构中收益