本文主要通过讨论传统的编程方法在软件的网络通信模块开发中的问题,提出利用ACE面向对象的设计模式和框架可以帮助开发者消除通信组件的复杂性。概述了ACE的反应器,事件处理器,接受器,连接器等框架,以及ACE在开发软件的数据传输和通信模块中的优越性,给出了一个简单的例子程序。
1引言
随着互联网及分布式思想的普及,开发高效的网络通讯组件变得越来越重要,传统的API函数虽然能满足基本的需求,但也有很多问题。网络通信面临着硬件平台,软件环境,网络协议等的多样性和异种性,使得开发过程的重复性高,也缺乏安全性、可移植性、和可扩充性,直接利用底层的API函数编写的网络数据传输程序在实际运行过程中极容易出错,并且代码难以维护,其传输的可靠性和稳定性也难以保障,ACE的出现能够很好的解决上述问题。
2ACE概述
ACE自适配通信环境(Adaptive Communication Environment)是一种面向对象(OO)的工具包,它实现了通信软件的许多基本的设计模式。ACE的目标用户是在UNIX和Win32平台上开发高性能通信服务和应用的开发者。ACE简化了使用进程间通信、事件多路分离、显式动态链接和并发的OO网络应用和服务的开发[1]。通过在运行时将服务与应用动态链接进应用,并在一个或多个进程或线程中执行这些服务,ACE使系统的配置和重配置得以自动化。
ACE被设计成为层次结构,在ACE框架中有三个基本层次[2]:
2.1操作系统适配层(ACE OS Adaptation)
它封装了原始的、基于C的OS API,隐藏了“和平台相关”的细节,展示了统一的OS机制接口,供更高级的ACE使用。它使ACE的较高层与平台依赖性屏蔽开来,从而使得通过ACE编写的代码保持了相对的平台无关性,方便ACE在不同操作系统平台的移植。
2.2C++包装层(ACE C++ Wrapper Facade)
ACE C++ Wrapper Facade位于ACE OS Adaptation之上,用于构建高度可移植的和类型安全的C++应用[3]。这是ACE工具包最大的一部分,它将底层的C函数包装成C++类,使之能够用于:并发和同步,IPC,内存管理,定时器类,容器类,信号处理,文件系统组件,线程管理,与此同时,降低了由于“安全性”和“可用性”的提高而带来的性能开销。
2.3框架和模式层(ACE Framework)
ACE Framework层属于高层,它集成并增强了较低层次的C++包装层,包括前摄器,反应器,任务连接器,接受器,事件处理器,服务配置器,消息队列等框架。消除了通信编程的复杂性,大大缩短应用程序的开发周期[4]。
3ACE的几大框架
ACE框架集成、扩充了C++ Wrapper Facade类,加强了“和应用相关的类”和“独立于应用的类”之间的集成与合作[3]。
3.1ACE_Reactor框架
软件的通信模块一般有很多不同的事件,例如定时器,I/O,信号,同步/异步等。ACE框架对事件的处理进行了统一,简化了事件驱动程序的开发。用它来检测来自各种事件源的事件的发生,并将事件多路分离给其预先登记的事件处理器,管理处理器所定义的挂钩方法,从而以一种应用定义的方式处理这些事件。同时,框架提供了稳定的接口,方便了扩展。
当要分派处理网络通信中的不同事件时,首先要注册相应的事件处理程序,所有的事件处理器必须由ACE_Event_Handler这个抽象接口实现。它包含了很多的handle_*方法,例如handle_input(输入事件),handle_output(输出事件),handle_signal(OS发出的信号),handle_timeout(定时器到期),handle_exception(异常事件)等。当ACE_Reactor管理的事件处理器上有登记过的事件发生时,反应器将自动的回调相应的方法。
3.2ACE Acceptor-Connector框架
接受器/连接器模式设计用于降低连接建立与连接建立后所执行的服务之间的耦合。它们利用工厂模式(Factory Pattern)将具体的网络连接操作委托给底层封装的函数进行处理,但是增强了安全性,和平台无关性,更重要的是增加了灵活性,使得开发过程更加方便和简单,回避了复杂繁琐极易出错的API函数。在这个框架中,接受器模式通过“ACE_Acceptor”这个助手工厂类实现,ACE_Acceptor工厂用于被动连接建立连接和建立后的处理。同样的,连接器模式通过“ACE_Connector”助手类实现,ACE_Connector工厂用于主动连接建立和连接建立后的处理。
3.3ACE_Task框架
ACE_Task是一个含有一或多个线程,以及一个底层消息队列的主动对象,利用这个抽象类来实现感兴趣的任务。我们如果创建自己的任务,就需要从ACE_Task类派生子类,然后分别实现open和close方法,在open方法中可以包含线程的初始化,内存分配,进程锁等必须的资源,用以实现任务的初始化。相应的,close方法是对应的终止方法,可以包含任务资源的回收代码等。然后在open方法中调用activate方法来启用svc方法,svc方法是任务中新的线程的启动点,服务特有的处理会在这个函数当中实现。
4数据传输实例
在一些软件模块中,数据的传输显得必不可少,尤其是行业里的重要数据文件(如txt形式的数据文件),经常需要将采集到的数据文件通过网络上传到指定的软件模块进行处理。以下将利用上述ACE的框架来构建一个在本机的客户端/服务器模式的数据传输模块。
4.1客户端(Client)模块
(1)初始化客户端的事件处理器,完成读取并发送文件的任务。从ACE_Svc_Handler派生自己的MyClientHandler,实现其中的open和handle_output方法。handle_output方法是在I/O设备输出缓冲区上有可用空间、并且新数据可以发送给它时被回调,在这个函数中读取数据文件,并发送。在open方法中得到全局的反应器单体(ACE_Reactor::instance()),并注册写事件(register_handler)。
(2)建立同服务器端的连接。通过ACE_Connector的connect方法,将事件处理器(MyClientHandler)的指针和远程服务器的地址(ACE_INET_Addr类型)传递给它,发起同服务器端的连接。最后进入反应器的事件循环(run_event_loop)。
4.2服务器端(Server)模块
(1)从ACE_Svc_Handler派生自己的服务处理器MyServiceHandler并初始化,实现其中的open和handle_input方法。handle_input方法是在OS内部的侦听队列上收到了客户的新连接请求时被回调,用来接收从客户端发来的数据,接收完成后停止反应器的事件循环(end_reactor_event_loop)。当连接建立时就会自动调用open方法。同样的,在open方法中注册读事件,并保持登记状态,只要有数据来就自动调用handle_input。
作者:朱尧 来源:计算机光盘软件与应用 2013年5期