`
jnn
  • 浏览: 288310 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

ACE是Service Config框架的实现分析

阅读更多

在开发和维护的过程中,很多时候会涉及一个问题,就是如何实现派生类的动态加载。由于C++本身不支持动态类的加载机制,需要通过配置文件描述服务信息并采用动态库来加载。因此在ACE中专门设计了service config框架来解决这样的问题。 

这篇文章主要讲述了在ACE中如果通过宏定义的方式实现服务的动态加载与配置。

 

在开发和维护的过程中,很多时候会涉及一个问题,就是如何实现派生类的动态加载。由于C++本身不支持动态类的加载机制,需要通过其他的方式来进行支持。因此在ACE中专门设计了service config框架来解决这样的问题。

service config框架,通过修改配置文件,能够实现对派生于ACE_Service_Object的服务对象的加载,在service config中根据加载服务代码方式的不同可以分为:

静态服务
  是被静态链接至应用程序的服务
动态服务
  是从一个和多个共享库中链接的服务

由于本文讨论的重点时动态类的加载机制,因此主要讨论service config中有关动态服务的实现,其他的实现内容,大家可以参考 C++NPV2中的第5章。

在这里主要是从原理方面,简单分析service config框架的实现。
在分析service config框架之前,需要明确service config需要实现的功能:
1.我们写的新的服务需要在运行时(不是在编译时)能够被service config框架识别以及调用。
2.其次是服务对象的生命周期由service config框架进行管理。
3.通过配置文件,来获知服务对象加载信息。

对于前面提到的两点功能,只需要我们写的服务类继承ACE_Service_Object ,实现这个类所提供的init(),fini(),suspend(),resume(),info()对服务管理的方法。由于ACE_Service_Object继承了ACE_Event_Handler,因此可以实现相关服务处理的方法。

对与第三点来说,如果是用Java语言来实现service config框架,那也很容易,可以通过动态类型识别(RTTI),在语言运行库中,就提过了描述Class信息的机制,使用著名的Class.forName(),可以获得需要加载类的主要信息。

而对于C++来说,这就比较麻烦了,主要是需要解决有关类信息描述的问题。对于DLL来说,如果直接将对象进行输出的话,由于C++所支持的重载机制,输出的类方法名会结合参数产生变化,如果想通过service config框架,加载DLL输出的类,就必须通过静态编译的方法,获知类的定义。而我们的要求是在程序运行时来,通过配置文件中定义的dll名,以及相关的类名来加载相关的服务类。

通过分析源码,我们可以发现一些有意思的东东。

# define ACE_Local_Service_Export

# define ACE_FACTORY_DEFINE(CLS,SERVICE_CLASS)
void _gobble_##SERVICE_CLASS (void *p) {
  ACE_Service_Object *_p = ACE_static_cast (ACE_Service_Object *, p);
  ACE_ASSERT (_p != 0);
  delete _p; }
extern "C" CLS##_Export ACE_Service_Object *
_make_##SERVICE_CLASS (ACE_Service_Object_Exterminator *gobbler)
{
  ACE_TRACE (#SERVICE_CLASS);
  if (gobbler != 0)
    *gobbler = (ACE_Service_Object_Exterminator) _gobble_##SERVICE_CLASS;
  return new SERVICE_CLASS;
}

/// The canonical name for a service factory method
#define ACE_SVC_NAME(SERVICE_CLASS) _make_##SERVICE_CLASS

/// The canonical way to invoke (i.e. construct) a service factory
/// method.
#define ACE_SVC_INVOKE(SERVICE_CLASS) _make_##SERVICE_CLASS (0)
//@}

/** @name Helper macros for services defined in the netsvcs library.
 *
 * The ACE services defined in netsvcs use this helper macros for
 * simplicity.
 *
 */
//@{
# define ACE_SVC_FACTORY_DECLARE(X) ACE_FACTORY_DECLARE (ACE_Svc, X)
# define ACE_SVC_FACTORY_DEFINE(X) ACE_FACTORY_DEFINE (ACE_Svc, X)
//@}

ACE_SVC_FACTORY_DECLARE (...)

在这里用...来代替具体的类名
_make_... (ACE_Service_Object_Exterminator *gobbler) 是dll输出的调用接口(注意是C方式进行输出的,如果是C++的话就另当别论了),我们需要在svc.conf中写出输出的调用函数名。

_make... 这个宏精妙之处就在于此,由于C++不支持reflect机制,为了能够让Service_Config类
在不做任何改变的情况下,就能创建相关的ACE_Service_Object 继承类的实例,_make提供了一个
创建类实例的方法。 这也许是Factory模式的另类应用,其实这个方法在某些环境还是很有效,
也可以帮助我们将C++的类对象输出至delphi中,供delphi进行调用。

return new SERVICE_CLASS;

这样就有人会问了,提供new,如何提供delete呢?
大家再看一下_gobble_...这个宏定义,
从 ACE_Service_Object_Exterminator *gobbler 的定义
typedef void (*ACE_Service_Object_Exterminator)(void *);
可知 ACE_Service_Object_Exterminator 是一个函数指针而gobbler定义是指向这个函数指针的指针。

通过给gobbler赋值,就可以给service config框架提供释放的ACE_Service_Object派生类的方法了。

还有为什么在_gobble_...函数中需要ACE_Service_Object *_p = ACE_static_cast (ACE_Service_Object *, p); 来一个强制转换呢?


强制转换是因为 _gobble_##SERVICE_CLASS (void *p)中的p是无类型指针,强制转换成ACE_Service_Object * 类型,delete *p 时,就可以调用p所指向的ACE_Service_Object子类的析构函数。

svc.conf 示例文件
dynamic Timer_Service_3 Service_Object *
./Timer:_make_Timer_Service_3()
"timer $INTERVAL $MAX_TIMEOUTS $TRACE"
里面没有有关_gobble_##SERVICE_CLASS 函数的描述,
这是因为_make_##SERVICE_CLASS 的宏定义中已经完成有关析构函数的注册工作了。

分享到:
评论

相关推荐

    C++ Network Programming, Volume 2: Systematic Reuse with ACE and Frameworks

    - 第5章介绍了ACE服务配置器框架,展示了如何使用ACE_Service_Object、ACE_Service_Repository和ACE_Service_Config类来动态配置和管理服务。 6. ACE任务框架 - 第6章讨论了ACE任务框架,重点讲解了ACE_Message_...

    VC6下配置ACE的详细过程

    ACE(Adaptive Communication Environment)是一个开源中间件框架,支持多种平台和操作系统。对于 Windows 平台上的开发人员来说,在 VC6 中配置 ACE 是一项常见的任务。 #### 二、创建 config.h 文件 1. **创建 `...

    linuxdds.pdf

    OpenDDS是基于DDS(Data Distribution Service)标准的开源实现,它依赖于ACE(Adaptive Communication Environment)和TAO(The Adaptive Communication Environment)框架。在本文中,我们将详细探讨如何在Linux...

    linuxdds.docx

    OpenDDS是一个开源的DDS实现,它依赖于ACE(Adaptive Communication Environment)和TAO(The Adaptive ORB)框架。下面是根据标题和描述中的内容,详细解释这些关键知识点: 1. **ACE+TAO框架**: ACE是一个C++库...

    ConfigurationManager

    在.NET框架中,`ConfigurationManager`是一个非常重要的工具类,它主要用于应用程序配置文件(如App.config或Web.config)的读取与管理。本文将深入探讨`ConfigurationManager`的基本概念、工作原理以及如何在实际...

    odoo12.0前端依赖.pdf

    7. **web.AbstractService** 和 **web.AbstractStorageService**:抽象服务和存储服务基类,为实现特定的服务和存储机制提供基础框架。 8. **web.Class** 和 **web.collections**:提供了面向对象编程的支持,以及...

    Windows 系统错误代码简单分析

    Microsoft Windows 系统错误代码简单分析:  0000 操作已成功完成。  0001 错误的函数。  0002 系统找不到指定的文件。  0003 系统找不到指定的路径。  0004 系统无法打开文件。  0005 拒绝访问。...

    RFC8519 YANG Data Model for Network Access Control Lists (ACLs)

    通过这种方式,ACLs能够实现对网络流量的精细化控制,比如限制某些IP地址的访问、过滤特定端口的流量等。 #### 定义与术语 在深入探讨之前,我们需要了解一些关键的定义和术语: - **规则(Rule)**:ACL中最基本...

Global site tag (gtag.js) - Google Analytics