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框架自动完成,是不是工作者线程越多越好呢? 答案是否定的。 多线程可以提高客户的响应速度。比如同时有A,B两个客户端先后发起两个请求,A请求完成的时间较长,B请求则可以很快完成,如果只有一个工作线程,那么B需要等待A请求完成以后才能收到自己的响应,对于A来说,它本来就不期待自己的请求很快被完成,实际的执行情况会是,A在期待的时间内收到响应,B则使用了A的时间才收到自己的响应,B的客户满意度就会很差。 如果使用多线程,A会延迟一点点收到自己的响应,而B也可以在合理的时间内收到自己的响应。 但是由于多线程有自己的开销,就整个系统来说,单工作线程执行A和B的总时间回比多工作线程执行AB任务的总时间要短。
对于领导者/跟随者模型中,必然存在一个对等的线程池,线程池的数目取决于系统能够承受的数目,单就对于模型本身来说,线程池的线程数目越大,能够承受的网络蜂拥的极限值也越大。 但是如果执行每个请求的时间都很短,则系统中存在大量永远也用不到的线程,浪费了系统的资源。
如果使用多处理器的系统,应用程序必然能够从多线程(工作线程和跟随者线程)结构中收益。
 
C++网络编程 ACE相关资料收集
2008-01-10 13:38
小飞驴的网站 http://www.flyingdonkey.com/ 马维达 C++网络编程 卷二 译者
LoveUnix技术论坛 http://www.loveunix.com/viewthread.php?tid=29276

hxh(贺星河)的专栏 http://blog.csdn.net/hxhbluestar/category/25379.aspx ACE网络编程

ACE自适配通信环境讨论 http://www.huihoo.org/chat/ace_20030702.html


[ACE技术论文集]一.ACE自适配通信环境:用于开发通信软件的面向对象网络编程工具包
ACE程序入口函数替换机制分析
[ACE技术论文集]二 包装外观(Wrapper Facade):用于在类中封装函数的结构型模式
精华帖标志
[ACE技术论文集]三 IPC SAP:用于高效、可移植和灵活的网络编程的C++包装
[ACE技术论文集]四 ACE轻量级OS并发机制的OO封装
[ACE技术论文集]五 C/C++线程专有存储:用于访问“per-Thread”状态的对象行为模式

ACE的类结构图[pdf文档]

ACE自适配通信环境

Douglas C. Schmidt


一、ACE综述

  ACE自适配通信环境(ADAPTIVE Communication Environment)是可以自由使用、开放源码的面向对象(OO)框架(Framework),在其中实现了许多用于并发通信软件的核心模式。ACE提供了一组丰富的可复用C++ Wrapper Facade(包装外观)和框架组件,可跨越多种平台完成通用的通信软件任务,其中包括:事件多路分离和事件处理器分派、信号处理、服务初始化、进程间通信、共享内存管理、消息路由、分布式服务动态(重)配置、并发执行和同步,等等。

ACE的目标用户是高性能和实时通信服务和应用的开发者。它简化了使用进程间通信、事件多路分离、显式动态链接和并发的OO网络应用和服务的开发。此外,通过服务在运行时与应用的动态链接,ACE还使系统的配置和重配置得以自动化。

ACE正在进行持续的改进。Riverace公司( http://www.riverace.com)采用开放源码商业模式对ACE进行商业支持。此外,ACE开发组的许多成员目前正在进行The ACE ORB(TAO, http://www.cs.wustl.edu/~schmidt/TAO.html)的开发工作。

二、使用ACE的好处

使用ACE的好处有:

l    增强可移植性:在ACE组件的帮助下,很容易在一种OS平台上编写并发网络应用,然后快速地将它们移植到各种其他的OS平台上。而且,因为ACE是开放源码的自由软件,你无需担心被锁定在特定的操作系统平台或编译器上。

l    更好的软件质量:ACE的设计使用了许多可提高软件质量的关键模式,这些质量因素包括通信软件灵活性、可扩展性、可复用性和模块性。

l    更高的效率和可预测性:ACE经仔细设计,支持广泛的应用服务质量(QoS)需求,包括延迟敏感应用的低响应等待时间、高带宽应用的高性能,以及实时应用的可预测性。

l    更容易转换到标准的高级中间件:TAO使用了ACE提供的可复用组件和模式。它是CORBA的开发源码、遵循标准的实现,并为高性能和实时系统作了优化。为此,ACE和TAO被设计为能良好地协同工作,以提供全面的中间件解决方案。

三、ACE的结构和功能

下图显示了ACE中的关键组件以及它们的层次关系:



图中的结构和各层的组成部分描述如下。

四、ACE OS适配层

该层直接位于用C写成的本地OS API之上。它提供轻型的类POSIX OS适配层,将ACE中的其他层及组件和以下与OS API相关联的平台专有特性屏蔽开来:

l    并发和同步:ACE的适配层封装了用于多线程、多进程和同步的OS API。

l    进程间通信(IPC)和共享内存:ACE的适配层封装了用于本地和远地IPC、以及共享内存的OS API。

l    事件多路分离机制:ACE的适配层封装了用于对基于I/O、定时器、信号和同步的事件进行同步和异步多路分离的OS API。

l    显式动态链接:ACE的适配层封装了用于显式动态链接的OS API。显式动态链接允许在安装时或运行时对应用服务进行配置。

l    文件系统机制:ACE的适配层封装了用于操作文件和目录的OS文件系统API。

ACE OS适配层的可移植性使得ACE可运行在许多操作系统上。ACE已在广泛的OS平台上进行了移植和测试,包括Win32(也就是,在Intel和Alpha平台,使用MSVC++、Borland C++ Builder和IBM Visual Age的WinNT 3.5.x、4.x、2000、Win95/98和WinCE)、Mac OS X、大多数版本的UNIX(例如,SPARC和Intel上的Solaris 1.x和2.x、SGI IRIX 5.x和6.x、DG/UX、HP-UX 9.x、10.x和11.x、DEC/Compaq UNIX 3.x和4.x、AIX 3.x和4.x、UnixWare、SCO,以及可自由使用的UNIX实现,比如Debian Linux 2.x、RedHat Linux 5.2、6.x和7.x、FreeBSD和NetBSD)、实时操作系统(比如,LynxOS、VxWorks、Chorus ClassiX 4.0、QnX Neutrino、RTEMS和PSoS)、MVS OpenEdition和CRAY UNICOS。

由于ACE的OS适配层所提供的抽象,所有这些平台使用同一棵代码树。这样的设计极大地增强了ACE的可移植性和可维护性。此外,还有Java版本的ACE可用( http://www.cs.wustl.edu/~eea1/JACE.html)。

五、OS接口的C++ Wrapper Facade

可以直接在ACE OS适配层之上编写高度可移植的C++应用。但是,大多数ACE开发者使用的是上图中所示的C++ Wrapper Facade层。通过提供类型安全的C++接口(这些接口封装并增强本地的OS并发、通信、内存管理、事件多路分离、动态链接和文件系统API),ACE Wrapper Facade简化了应用的开发。应用可以通过有选择地继承、聚合和/或实例化下面的组件来组合和使用这些包装:

l    并发和同步组件:ACE对像互斥体和信号量这样的本地OS多线程和多进程机制进行抽象,以创建高级的OO并发抽象,像主动对象(Active Object)和多态期货(Polymorphic Future)。

l    IPC和文件系统组件:ACE C++包装对本地和/或远地IPC机制进行封装,比如socket、TLI、UNIX FIFO和STREAM管道,以及Win32命名管道。此外,ACE C++包装还封装了OS文件系统API。

l    内存管理组件:ACE内存管理组件为管理进程间共享内存和进程内堆内存的动态分配和释放提供了灵活和可扩展的抽象。

ACE C++包装提供了许多与ACE OS适配层一样的特性。但是,这些特性是采用C++类和对象、而不是独立的C函数来构造的。这样的OO包装有助于减少正确地学习和使用ACE所需的努力。

例如,C++的使用提高了应用的健壮性,因为C++包装是强类型的。所以,编译器可在编译时、而不是运行时检测类型系统违例。相反,不到运行时,不可能检测像socket或文件系统I/O这样的C一级OS API的类型系统违例。

ACE采用了许多技术来降低或消除额外的性能开销。例如,ACE大量地使用C++内联来消除额外的方法调用开销;这样的开销可由OS适配层和C++包装所提供的额外的类型安全和抽象层次带来。此外,对于性能要求很高的包装,比如socket和文件I/O的send/recv方法,ACE会避免使用虚函数。

六、框架

ACE还含有一个高级的网络编程框架,集成并增强了较低层次的C++ Wrapper Facade。该框架支持将并发分布式服务动态配置进应用。ACE的框架部分包含以下组件:

l    事件多路分离组件:ACE Reactor(反应器)和Proactor(前摄器)是可扩展的面向对象多路分离器,它们分派应用特有的处理器,以响应多种类型的基于I/O、定时器、信号和同步的事件。

l    服务初始化组件:ACE Acceptor(接受器)和Connector(连接器)组件分别使主动和被动的初始化任务与初始化一旦完成后通信服务所执行的应用特有的任务去耦合。

l    服务配置组件:ACE Service Configurator(服务配置器)支持应用的配置,这些应用的服务可在安装时和/或运行时动态装配。

l    分层的流组件:ACE Stream组件简化了像用户级协议栈这样的由分层服务组成的通信软件应用的开发。

l    ORB适配器组件:通过ORB适配器,ACE可以与单线程和多线程CORBA实现进行无缝集成。

ACE框架组件便利了通信软件的开发,它们无需修改、重编译、重链接,或频繁地重启运行中的应用,就可被更新和扩展。在ACE中,这样的灵活性是通过结合以下要素来获得的:(1)C++语言特性,比如模板、继承和动态绑定,(2)设计模式,比如抽象工厂、策略和服务配置器,以及(3)OS机制,比如显式动态链接和多线程。

七、分布式服务和组件

除了OS适配层、C++ Wrapper Facade和框架组件,ACE还提供了包装成自包含组件的标准分布式服务库。尽管这些服务组件并不是ACE框架库的严格组成部分,它们在ACE中扮演了两种角色:

1.    分解出可复用分布式应用的“积木”:这些服务组件提供通用的分布式应用任务的可复用实现,比如名字服务、事件路由、日志、时间同步和网络锁定。

2.    演示ACE组件的常见用例:这些分布式服务还演示了怎样用像Reactor、Service Configurator、Acceptor和Connector、Active Object,以及IPC包装这样的ACE组件来有效地开发灵活、高效和可靠的通信软件。

八、高级分布式计算中间件组件

即使使用像ACE这样的通信框架,开发健壮、可扩展和高效的通信应用仍富有挑战性。特别是,开发者必须掌握许多复杂的OS和通信的概念,比如:

l    网络寻址和服务标识。

l    表示转换,比如加密、压缩和在异种终端系统间的字节序转换。

l    进程和线程的创建和同步。

l    本地和远地进程间通信(IPC)机制的系统调用和库例程。

通过采用像CORBA、DCOM或Java RMI这样的高级分布式计算中间件,可以降低开发通信应用的复杂性。高级分布式计算中间件驻留在客户端和服务器之间,可自动完成分布式应用开发的许多麻烦而易错的方面,包括:

l    认证、授权和数据安全。

l    服务定位和绑定。

l    服务注册和启用。

l    事件多路分离和分派。

l    在像TCP这样的面向字节流的通信协议之上实现消息帧。

l    涉及网络字节序和参数整编(marshaling)的表示转换问题。

为给通信软件的开发者提供这些特性,在ACE中绑定了下面的高级中间件应用:

1.    The ACE ORB(TAO):TAO是使用ACE提供的框架组件和模式构建的CORBA实时实现,包含有网络接口、OS、通信协议和CORBA中间件组件等特性。TAO基于标准的OMG CORBA参考模型,并进行了增强的设计,以克服传统的用于高性能和实时应用的ORB的缺点。TAO像ACE一样,也是可自由使用的开放源码软件。

2.    JAWS:JAWS是高性能、自适配的Web服务器,使用ACE提供的框架组件和模式构建。JAWS被构造成“框架的框架”。JAWS的总体框架含有以下组件和框架:事件多路分派器、并发策略、I/O策略、协议管道、协议处理器和缓存虚拟文件系统。每个框架都被构造成一组协作对象,通过组合和扩展ACE中的组件来实现。JAWS也是可自由使用的开放源码软件。

九、主页

ACE的主页为: http://www.cs.wustl.edu/~schmidt/ACE.html,在这里可获得最新版本的ACE以及其他相关资源。


=======================================
网络通信

ACE

参考网站: http://www.c'>http://www.c'>http://www.c'>http://www.cs.wustl.edu/~schmidt/ACE.html

C++库的代表,超重量级的网络通信开发框架。ACE自适配通信环境(Adaptive Communication Environment)是可以自由使用、开放源代码的面向对象框架,在其中实现了许多用于并发通信软件的核心模式。ACE提供了一组丰富的可复用C++包装外观(Wrapper Facade)和框架组件,可跨越多种平台完成通用的通信软件任务,其中包括:事件多路分离和事件处理器分派、信号处理、服务初始化、进程间通信、共享内存管理、消息路由、分布式服务动态(重)配置、并发执行和同步,等等。

StreamModule

参考网站: http://www.omnifarious.org/StrMod/'>http://www.omnifarious.org/StrMod/

设计用于简化编写分布式程序的库。尝试着使得编写处理异步行为的程序更容易,而不是用同步的外壳包起异步的本质。

SimpleSocket

参考网站: http://home.hetnet.nl/~lcbokkers/simsock.htm

这个类库让编写基于socket的客户/服务器程序更加容易。

A Stream Socket API for C++

参考网站: http://www.pcs.cnu.edu/'>http://www.pcs.cnu.edu/~dgame/sockets/socketsC++/sockets.html

又一个对Socket的封装库。
 

from http://www.acejoy.com ACE网络编程开发网
author: kylin
大家好,第一次来这个属于ACEer的地方真的很高兴啊!下面就ACE中现有的三种Reactor做一些总结,都是我个人使用的经验,如有不妥还请指教。
最近,偶在ACE_Reactor框架和ACE_Proactor框架的基础上写了一个网络应用框架,主要目的是将网络数据收发,网络错误处理,以及网络超时这些socket级的问题与应用逻辑分开,可以保证在应用逻辑的实现不变的情况下,随意改变网络层的实现(也就是用同步IO的ACE_Reactor框架或者用ACE_Proactor框架实现socket上的数据收发,超时及错误处理)。写这个网络应用框架的过程中遇到了很多问题,不得不去看ACE_Reactor框架和ACE_Proactor框架的源代码,所以最后对这两个框架有了更深的认识。下面说说ACE_Reactor框架,都是我个人使用的经验,如有不妥还请指教。
现有的ACE库中提供了三种主要的Reactor实现(更多新的实现到官方网站上应该可以找到),ACE_Select_Reactor, ACE_TP_Reactor和ACE_WFMO_Reactor。三种实现的使用都有不同的注意事项:
(1)ACE_WFMO_Reactor:这个实现是基于Win32的Socket Event-select模型,也就是用一个win32 的手动重置event与一个socket相关联(调用WSAEventSelect函数并指明关心哪些socket事件,如可读,可写等),用WaitForMutiple0bjects来实现多路IO监视,当这个函数返回后调用WSAEnumNetworkEvents检查socket上发生了那种事件(可读或可写)。   这个实现问题最大。 首先,它的致命伤在于每一个ACE_WFMO_Reactor只能同时监视64个socket(具体说是62个,有2个用于notify()和参与event-loop线程的唤醒同步);其次,就是它的可写条件非常诡异,只有当socket内部写缓冲区从满到不满时才算可写,因此,向它register_event 写事件时不出意外的话一定出错(第一次写成功,以后就再写不了了)。因此,这个实现用途很有限。不过,这个实现可以保证多个线程同时对同一个reactor执行event_loop,为了达到这个目的,它在多线程同步上下了很多工夫,读它的源代码会是很好的学习机会(牛人写的就是不一样啊,win32 event的使用简直是登峰造极)。
(2)ACE_Select_Reactor:这个实现中归中举,不要忘记在线程执行event_loop前成为这个reactor的owner。值得学习的是实现中使用的那把锁的实现, 即ACE_Token类,以后自己写程序的时候可以用得上,比mutex强很多。另外就是notify()的实现,也就是那个ACE_Pipe类,说白了就是本地回环socket来实现线程间通信。这个实现和(1)可以在其他线程(也就是没有执行Reactor_Event_Loop的线程)中安全的调用Remove_Handler,这个很方便,一般就可以在handle_close()方法里面做清理handler的工作。但是有一个问题注意,要自己跟踪每个handler注册了那些事件,只有向reactor注销了这些时间后才能delete这个handler。这个问题在C++ NPv2中强调过。这个实现默认是可以同时监视1024个socket,不过可惜的是只能一个线程执行Reactor_Event_Loop。
(3)ACE_TP_Reactor:这个是我最喜欢的了,但是如果不清楚它的实现的话会很容易出错。如果你使用了多个线程run_reactor_event_loop:首先,在默认情况下,你不能象前两个实现那样在不需要某个handler的情况下安全的调用remove_handler();其次,你需要在handle_input(),和handle_timeout()以及handle_output(),和handle_timeout()中考虑同步,注意是handle_**put与handle_timeout()之间才有同步问题,而handle_input()和handle_output()之间不用考虑。解决第一个问题的办法是在ACE_Event_handler中启动reference_count,并且改变删除策略:在handle_close()中不进行任何清除工作,而是将ACE_Event_handler的reference_count减一,而清除工作应该在析构函数中进行。那么,delete是谁调用呢---是reactor框架ACE_Event_handler在reference_count为0时帮你调用。总之,这个实现的使用要比其他的复杂。
总之,Reactor的使用远比那几本书上讲的要复杂得多,如果不彻底了解它是怎么实现的,在使用过程中难免会碰到许多问题。所以,我的建议是,看源代码!这样不仅可以深入理解Reactor框架,少犯错误,还可以学习大牛们怎么写程序的,特别是对于设计模式,还有操作系统API的灵活使用。关于ACE_Proactor的下次再聊。


提一些自己的看法,大家讨论。

1、ACE_WFMO_Reactor部分,向它register_event 写事件时不出意外的话一定出错,应用中没发现,因为这个实现中, 事件在当前状态变化时候触发,而不是基于当前状态触发。所以,注册了写标志后,你就一直发送就行了,直到它告诉你不成了,再等待handle_output()被触发。
2、ACE_Select_Reactor部分,不过可惜的是只能一个线程执行Reactor_Event_Loop,这个不准确。准确的说,是在某一时刻只能被一个线程执行。可以使用多个线程,但是每个线程循环中必须使用owner()方法设置所有者线程。