ACE Service Configurator配置动态服务

 

1.     导出dll制作步骤

可以参考<<ACE程序员指南>>p25dll制作,在此基础上,增加67

1)制定dll名称,例如AgentService(.dll)

2)generate_export_file.pl AgentService 生成自定义的AgentServiceExport.h头文件

3)dll的工程main函数所在的源文件包含所程程的AgentServiceExprot.h头文件

4)  在进行类的声明时,在class关键字和类名之间插入关键字AgentService_Export
注:若本身就是dll工程,则不需要该关键字

5)在编译DLL的源文件时,定义宏AgentService_BUILD_DLL

6)  DLL的源文件中加入如下宏
ACE_FACTORY_DEFINE (AgentService, AgentServer)
AgentService
dll名称,AgentServerdll中具体实现类的名称

7)编写svc.conf文件,供调用exe使用,格式为
dynamic AgentService Service_Object * AgentService:_make_AgentServer() "AgentServer.xml"

 

2.     调用者exe制作步骤

1)如果是console,则main函数中举例如下
#include <WINSOCK2.H>

#include <atlbase.h>

#include <ace/OS.h>

#include <ace/Object_Manager.h>

#include <ace/Service_Config.h>

#include <ace/Service_Repository.h>

#include <ace/Service_Object.h>

 

#include <windows.h>

 

int main(int argc, char* argv[])

{

CoInitialize(NULL);

    ACE::init();

   

    ACE_TCHAR path[MAX_PATH];

    ACE_TCHAR cwd[MAX_PATH];

 

    ::GetModuleFileName(GetModuleHandle(NULL), path, MAX_PATH);

    //LogEvent(path);

    ACE_TCHAR* ptr = path + ACE_OS::strlen(path);

    while(*ptr != TEXT('/') && *ptr != TEXT('//') && *ptr != TEXT(':')){

        --ptr;

        if(ptr == path) {

            break;

        }

    }

    *(++ptr) = '/0';

 

    //::SetCurrentDirectory(path);

 

    ACE_OS::getcwd(cwd, MAX_PATH);

    ACE_OS::chdir(path);

 

    int argcSvc = 4;

    ACE_TCHAR *argvSvc[4] = {

        ACE_TEXT("OnmiService"),

        ACE_TEXT("-d"),

        ACE_TEXT("-f"),

        ACE_TEXT("svc.conf")

    };

//  argv[3] = path;

    if(ACE_Service_Config::open(argcSvc, argvSvc) == -1) {

        ACE_DEBUG((LM_ERROR, ACE_TEXT("start ace_service_config failed/n")));

    }

 

while(1){

        cin >> ch;

        if(ch == 'q' || ch == 'Q')

        {

            ACE_DEBUG ((LM_INFO, ACE_TEXT (" | %t | %N %l | Stop OnmiConsole!/n")));

            ACE_Service_Config::fini_svcs();

            break;

        }

}

    CoUninitialize();

    return 0;

}

 

2)如果是基于MFCdialog应用,则需要创建一线程启动起dll

m_pConfigService = DYNAMIC_DOWNCAST(CConfigService, AfxBeginThread(RUNTIME_CLASS(CConfigService)));

    if(m_pConfigService == NULL)

    {

        AfxMessageBox("Start Agent Service failed");

        return -1;

    }

 

class CConfigService : public CWinThread

{

}

CConfigService的实现,参考AGSD工程中ConfigService.hConfigService.cpp文件

 

 

 

///

//ConfigService.h

 

#pragma once

 

// CConfigService

 

class CConfigService : public CWinThread

{

    DECLARE_DYNCREATE(CConfigService)

 

protected:

    CConfigService();           // 动态创建所使用的受保护的构造函数

    virtual ~CConfigService();

 

public:

    virtual BOOL InitInstance();

    virtual int ExitInstance();

    virtual int Run( );

 

    BOOL Stop(void);

 

    FILE * GetOutStream();

 

    BOOL m_isRun;

 

protected:

    DECLARE_MESSAGE_MAP()

 

private:

    FILE * m_out;

 

};

 

 

 

// ConfigService.cpp : 实现文件

//

 

#include "stdafx.h"

#include "AGSD.h"

 

#include "ConfigService.h"

 

#include <ace/OS.h>

#include <ace/Object_Manager.h>

#include <ace/Service_Config.h>

#include <ace/Service_Repository.h>

#include <ace/Service_Object.h>

#include <ace/Reactor.h>

 

 

// CConfigService

 

IMPLEMENT_DYNCREATE(CConfigService, CWinThread)

 

CConfigService::CConfigService()

: m_out(NULL)

{

}

 

CConfigService::~CConfigService()

{

}

 

BOOL CConfigService::InitInstance()

{

    ACE::init();

   

    errno_t err = freopen_s( &m_out, "freopen.out", "w+", stdout );

    if(err != 0)

    {

        AfxMessageBox(TEXT("Redirection error!"));

    }

 

    return TRUE;

}

 

int CConfigService::Run( )

{

    ACE_TCHAR path[MAX_PATH];

    ACE_TCHAR cwd[MAX_PATH];

 

    ::GetModuleFileName(GetModuleHandle(NULL), path, MAX_PATH);

    //LogEvent(path);

    ACE_TCHAR* ptr = path + ACE_OS::strlen(path);

    while(*ptr != TEXT('/') && *ptr != TEXT('//') && *ptr != TEXT(':'))

    {

        --ptr;

        if(ptr == path) {

            break;

        }

    }

    *(++ptr) = '/0';

 

    //::SetCurrentDirectory(path);

 

    ACE_OS::getcwd(cwd, MAX_PATH);

    ACE_OS::chdir(path);

 

    int argcSvc = 4;

    ACE_TCHAR *argvSvc[4] = {

        ACE_TEXT("OnmiService"),

        ACE_TEXT("-d"),

        ACE_TEXT("-f"),

        ACE_TEXT("svc.conf")

    };

   

    if(ACE_Service_Config::open(argcSvc, argvSvc) == -1) {

        ACE_DEBUG((LM_ERROR, ACE_TEXT("start ace_service_config failed/n")));

    }

   

    m_isRun = TRUE;

    return ACE_Reactor::instance()->run_reactor_event_loop ();

}

 

int CConfigService::ExitInstance()

{

    freopen( "CON", "w", stdout );

 

    return CWinThread::ExitInstance();

}

 

BEGIN_MESSAGE_MAP(CConfigService, CWinThread)

END_MESSAGE_MAP()

 

 

// CConfigService 消息处理程序

BOOL CConfigService::Stop(void)

{

    ACE_Reactor::instance()->end_event_loop ();

    return 0;

}

 

FILE * CConfigService::GetOutStream()

{

    return stdout;

}

 

 

 

3.     解释说明

3.1. 建立工程说明

1)若本身就是dll工程的话,且有DllMain入口函数,则不需要对AgentServer类进行导出声明 AGENTSERVICE_Export

2)只有从console改造过来的工程,而且没有main函数或者是DllMain函数,则需要对AgentServer类进行导出声明,声明符号为 AGENTSERVICE_Export,具体的符号需要使用$ACE_ROOT/bin/generate_export_file.pl AgentService 命令进行导出(AgentServciedll名称)

 

3.2. ACE_FACTORY_DEFINE(CLS,SERVICE_CLASS)

  对于ACE_FACTORY_DEFINE (AgentService, AgentServer)宏的解释

  AgentService:  CLS-是程序/库用来导入/导出声明的标识符. 取决于使用上述命令生成Export头文件时传入的参数,并与参数保持一致。

  AgentServer: SERVICE_CLASS是从ACE_Service_Object派生的类的名称,它会在服务初始化时被实例化,并于内部需要导出的实现类名保持一致。

 

3.3. 配置文件svc.conf

svc.conf格式

dynamic ident Service_Object * lib-pathname : factory-func() [active|inactive] [parameters]

 

实例

dynamic AgentService Service_Object * AgentService:_make_AgentServer() "AgentServer.xml"

 

其中AgentService为标识符,可以起另外的名字

AgentService代表dll名称

_make_AgentServer()中的AgentServerdll中实现类的名称

"AgentServer.xml"为参数名称

 

4.     举例

Visual C++ACE动态服务配置入门
摘要:
  
服务动态配置在编写服务端应用在有很明显的优点,本文简要介绍用visual C++ (7.1)
编写ACE动态服务的步骤。
  
本文适用于ACE初学者。
  
1.
主进程

1.1 创建主程序
   
Viusal Studio创建一空Win32 Console项目,这里命名为GLIVR86ServiceD.注,这里
D
表示Daemon,不是Debug。表示我们以后会把这个项目改造为了NT_Service(以后介绍步骤.
1.2
修改项目属性 (Configuation Properties)
1.2.1
为项目新增主文件 GLIVR86ServiceD.cpp,目的是为项目属性中,增加C/C++选项
1.2.1 General
修改程序输出路径$(OutDir)
1.2.2.Debugging  Command Arguments: -d,
以调试模式启动
1.2.3 C/C++
设置
1.2.3.1 Additional Include Directories /I[path]: $(ACE_ROOT);
1.2.3.2 Code Generation: /MTd ;/MT
调试版选MTd,发行版选 MT
1.2.3.3 Preprocessor:Preprocesor Definitions/D: WIN32;_DEBUG;_CONSOLE;
              
这是调试版,发行版将_DEBUG改为NDEBUG
1.2.4
链接设置
1.2.4.1 Input: Additinal Dependencise: ACE(d).lib,
调试版选aced.lib,
                                                  
发行版选ace.lib
1.2.4.2 System: SubSystem /subsystem: Console ;   (/SUBSYSTEM:CONSOLE)

主程序代码


 

// @file:  GLIVR86ServiceD.cpp 
//
@description:  IVR 86
业务服务主程序入口
//
@author: jiangtao
//
@version:2.0.0

#include 
" stdafx.h "
#include 
< memory >    //  
使用 auto_ptr

#include 
" ACE/OS_NS_unistd.h "
#include 
" ACE/TP_Reactor.h "
#include 
" ACE/Reactor.h "
#include 
" ACE/Service_Config.h "
#include 
" ACE/Thread_Manager.h "

//
线程池
static  ACE_THR_FUNC_RETURN event_loop ( void   * arg) 
{
    ACE_DEBUG((LM_INFO,
" (%P|%t),event_loop()/n " ));
    ACE_Reactor 
* reactor  =  static_cast < ACE_Reactor  *>  (arg);

    reactor
-> owner (ACE_OS::thr_self ());
    reactor
-> run_reactor_event_loop ();
    
return   0 ;
}


int
ACE_TMAIN (
int  argc, ACE_TCHAR  * argv[])
{
  
    
const  size_t N_THREADS  =   4 ;
    ACE_TP_Reactor tp_reactor;
    ACE_Reactor reactor (
& tp_reactor);
    auto_ptr
< ACE_Reactor >  delete_instance(ACE_Reactor::instance ( & reactor));
   
     
if  (ACE_Service_Config::open (argc, argv)  ==   - 1 )
            ACE_ERROR_RETURN ((LM_ERROR,
            ACE_TEXT (
" %p/n " ),
            ACE_TEXT (
" open " )),
            
1 );
       
    ACE_Thread_Manager::instance ()
-> spawn_n
                 (N_THREADS, event_loop, ACE_Reactor::instance ());

    ACE_Thread_Manager::instance ()
-> wait ();

    
return   0 ;
}


2.
创建被加载的服务的动态链接库
2.1
Visual Studio创建一个新的项目GLIVR86Service,我们依然从空白的Win32 Console

1.2.1
为项目新增主文件 GLIVR86Service.cpp,目的是为项目属性中,增加C/C++选项
1.2.1 General : Configration Type:
改为 动态链接库 Dynamic Library(DLL)
1.2.3.1 Additional Include Directories /I[path]: $(ACE_ROOT);
1.2.3.2 Code Generation: /MTd ;/MT
调试版选MTd,发行版选 MT
1.2.3.3 Preprocessor:Preprocesor Definitions/D:
                        WIN32;_DEBUG;_WINDOWS;ACE_BUILD_SVC_DLL
                       
这是调试版,发行版将_DEBUG改为NDEBUG
       
这里,特别注意,要增加 ACE_BUILD_SVC_DLL宏。如果用generate_export_file.pl
       
生成自定义的export头文件,这个宏也可以自定义
       
2.2.2
链接器设置
2.2.2.1 Input: Additinal Dependencise: ACE(d).lib,
调试版选aced.lib,
                                                  
发行版选ace.lib
2.2.2.2 System: SubSystem /subsystem: Console ;   (/SUBSYSTEM:CONSOLE)
2.2.2.3 General ,Output file:
                 ../GLIVR86ServiceD/GLIVR86ServiceD/GLIVR86ServiceD.dll
   
                   
这里填写上GLIVR86ServiceD的路径或环境变量Path中指
                   
示的路径,这样可以方便调试

2.2.2.4 Adanced, Import Libaray:  $(OutDir)/GLIVR86ServiceD.lib
                              
上面是调试版,发行版可以去掉后缀D,
                               $(OutDir)/GLIVR86Service.lib
                              
3.
服务的动态链接库实现

3.1 为项目增加两个文件,分别声明和实现服务类工厂
//@file: ServiceFactory.h
//@file: ServiceFactory.cpp
代码分别如下

 

// @file: ServiceFactory.h
//
@description:  IVR 86
业务服务
//
@author: jiangtao
//
@data: 2006-7-3
//
@version:1.0.0


#ifndef SERVICEFACTORY_H
#define  SERVICEFACTORY_H
#include 
" ACE/svc_export.h "
#include 
" ACE/Service_Config.h "
#include 
" ACE/Service_Object.h "

//
声明服务工厂
ACE_SVC_FACTORY_DECLARE (ServiceFactory_T)

class  ACE_Svc_Export ServiceFactory_T :  public  ACE_Service_Object
{
public :
  
///  Initializes object when dynamic linking occurs.
   virtual   int  init ( int  argc, ACE_TCHAR  * argv[]);

  
///  Terminates object when dynamic unlinking occurs.
   virtual   int  fini ( void );

  
///  Returns information on a service object.
   virtual   int  info (ACE_TCHAR  ** info_string, size_t length  =   0 const ;

};


#endif  /* SERVICEFACTORY_H */



/*******************************************************************/

// @file: ServiceFactory.cpp

#include 
" ServiceFactory.h "
#include 
" ACE/Log_Msg.h "
//
实现服务工厂
ACE_SVC_FACTORY_DEFINE (ServiceFactory_T)

int  ServiceFactory_T::init( int  argc, ACE_TCHAR  * argv[])
{
    ACE_DEBUG((LM_INFO,
" (%P|%t) 
服务初始化完成/n " ));
    
return   0 ;
}

int  ServiceFactory_T::info(ACE_TCHAR  ** strp, size_t length)  const
{
    ACE_DEBUG((LM_INFO,
" ServiceFactory_T::info() /n " ));
    
return   0 ;
}

int  ServiceFactory_T::fini( void )
{
    
return   0 ;
}


5.
服务配置文件svc.conf
dynamic IVR86Service Service_Object * GLIVR86Service: _make_ServiceFactory_T() active
   
6.
运行结果

 

 

5. 另一举例配置动态服务

ACE Service Configurator框架更强大的功能表现在配置动态服务上。如果在运行时收到指示,动态服务器可以从共享库(DLL)中动态加载。这种能力允许你在运行时替换服务,从而提供极大的灵活性。

ACE Service Configurator框架简化了全部的冗余工作。我们只需要按照设计规格实现我们需要的服务,把它载入到一个动态链接库中,编辑配置文件即可。换句话说:我们只需要创建一个合乎规格的动态链接库,然后在上例的svc.conf里面添加一两行指令,再次运行该程序即可加载此动态服务,我们甚至不需要对该程序进行重新编译。

动态链接库Mydll

5.1.    确定我们将要设计的动态链接库名字为Mydll

5.2.    运行$ACE_ROOT/bin/generate_export_file.pl Mydll,将输出写入Mydll_Export.h中去。

设计我们的服务的类,在类的源文件中包含该文件,并将关键字

i nclude “Mydll_Export.h”

 

class  Mydll_Export MyDynamicObj : public ACE_Service_Object 

{

public:

       MyDynamicObj();

       virtual ~MyDynamicObj();

 

       virtual int init (int argc, ACE_TCHAR *argv[])

       {

              printf("MyDynamicObj::init------/n");

              return 0;

       }

 virtual int fini()

       {

        

              printf("MyDynamicObj::fini-----/n");

              return 0;

       } 

};

 

ACE_FACTORY_DEFINE(Mydll,MyDynamicObj)

 

5.3. 编译,并在svc.conf里面加入如下指令,再运行,发现动态服务已被加载、移除。

dynamic MyDynamicObj Service_Object* Mydll:_make_MyDynamicObj() ""

 remove MyDynamicObj

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值