天天看點

ACE Service Configurator配置動态服務1.     導出dll制作步驟2.     調用者exe制作步驟3.     解釋說明4.     舉例5. 另一舉例配置動态服務

1.     導出dll制作步驟

可以參考<<ACE程式員指南>>p25,dll制作,在此基礎上,增加6和7

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名稱,AgentServer為dll中具體實作類的名稱

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)如果是基于MFC的dialog應用,則需要建立一線程啟動起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.h和ConfigService.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 指令進行導出(AgentServcie為dll名稱)

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()中的AgentServer為dll中實作類的名稱

"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  

// @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

繼續閱讀