Ice笔记-利用Ice::Service类简化Ice应用

本文深入介绍了Ice::Service类,它是Ice框架中用于实现系统服务的关键组件。与Ice::Application相比,Ice::Service提供了更为便捷的方式来运行后台服务或守护进程,并且详细解释了如何通过命令行选项来控制其行为。
摘要由CSDN通过智能技术生成

一.概要

一般而言, Ice::Application 类对 Ice 和服 器来 已经 非常方便 但在有些情况下, 用可能需要作 Unix 看守( daemon )或 Win32 运行在系 这样 的情况, Ice 提供了 Ice::Service 一个可与 Ice::Application 相比的 ,但它 封装了低 的、 针对 特定平台的初始化和关 ——系 常常需要使用 这样 的步

 
Ice::Application 的异同
1. Ice::Application Ice::Service 的功能类似,抽象出模型也相近。
但Ice::Service 的含义是让一个 应用 用比 Ice::Application 更好的管理形式 ――“服务”的方式运行。
不会、也不需要在
Ice::Application 中包含多个 Ice::Service
 
2. Ice::Service
的需用户继承的核心函数为 start() Ice::Application 需用户继承的核心函数为 run() ,不能混淆, 因为 Ice::Service也有一个run()函数
 
3. Ice ::Service
隐含了对 Service 的结束 通过 run() 中调用 waitForShutdown () ),无需用户显式使用类似 ic-> waitForShutdown () Ice::Application 必须主动在其 run() 函数中显式等待。可以说, Ice::Service Ice::Application 提供了更贴心的服务,但换个角度来说, Ice::Application 更何尝不是给用户提供了更好灵活性和简洁性。

4. Ice::Application 对信号的支持要好于 Ice::Service 。双方都能过滤 SIGHUP 信号。

就代码而言,感觉是这两个类不是同一个人写的 。因为这两个类之间可互相补充的东西不少,甚至可以合并为同一个类。不知到ZeroC是基于何种考虑?

 
类成员

下面是 Ice::Service 的定 为方便起见 将所有的虚函数都并列在一起。

class  ICE_API Service
{
public :
    Service();
    
virtual   ~ Service();

    
//  关闭服务,默认操作是关闭服务所使用的Ice通信器
    
//  如果你需要其它的附加操作,继承并改写此函数
     virtual   bool  shutdown();

    
//  信号回调函数,表示Service被信号所中断,默认操作是调用shutdown()函数
     virtual   void  interrupt();

    
//  供给IceUtil::CtrlHandler注册的原始信号处理函数
    
//  它处理完SIGHUP后调用interrupt。一般无需继承和改写,除非你想自己处理SIGHUP
     virtual   void  handleInterrupt( int );

protected :
    
//  允许子类执行它的启动活动,比如扫描所提供的参数向量、识别命令行选项,创建对象 //  适配器,以及注册servants。
    // 如果启动成功,子类必须返回true,否则返回false。
    
//  一般必须继承,并在其中实现应用自己的应用逻辑。
     virtual   bool  start( int char * [])  =   0 ;

    
//  阻塞等待Service的关闭。缺省操作是调用Ice通信器的waitForShutdown()。
     virtual   void  waitForShutdown();

    
//  服务停止清理函数。决定了main()的返回值,缺省操作返回true。
    
//  如果你有其它资源需要清理,需要继承并改写该函数。
     virtual   bool  stop();

    
//  初始化Service所用的Ice通信器
    
//  Service类提供了一个方法让用户决定Ice通信器的构造方式
     virtual  Ice::CommunicatorPtr initializeCommunicator( int & char * [],  const  InitializationData & );

    
//  日志相关函数
     virtual   void  syserror( const  std:: string & );
    
virtual   void  error( const  std:: string & );
    
virtual   void  warning( const  std:: string & );
    
virtual   void  trace( const  std:: string & );
    
virtual   void  print( const  std:: string & );

public :
    
    
//  服务入口函数,处理服务安装、卸载和run()的调用
     int  main( int & char * [],  const  InitializationData &   =  InitializationData());
    
int  main(StringSeq & const  InitializationData &   =  InitializationData());
    
//
    
//  返回服务使用的Ice通信器
    Ice::CommunicatorPtr communicator()  const ;
    
//
    
//  返回服务的惟一实例,注意实例是静态提供的。
     static  Service *  instance();
    
//
    
//  判断当前运行模式。如果是以Win32服务或linux daemon方式运行,返回true.
    
//  否则返回false
     bool  service()  const ;

    
//  返回当前Service名字,等同于Ice::Application::appName()
    std:: string  name()  const ;

    
//  检查当前平台是否支持后台运行(win32服务/linux daemon)
     bool  checkSystem()  const ;

    
//  Service的真正执行函数    
     int  run( int & char * [],  const  InitializationData &   =  InitializationData());

protected :
    
//  允许信号中断
     void  enableInterrupt();
    
//  禁止信号中断
     void  disableInterrupt();

private :

    Ice::LoggerPtr _logger;    
//  Service使用的Log对象
    Ice::CommunicatorPtr _communicator;  //  Services使用的通信器
     bool  _nohup;         //  是否忽略SIGHUP函数
     bool  _service;         //  Service运行模式是否为服务/daemon
    std:: string  _name;     //   Service应用名
  
    
static  Service *  _instance;  //  Service的惟一静态实例
};

 

四.用法举例

虽然 Ice::Service 可改写的行为较多,但一般情况下,只需改写: start(), stop() interrupt () 。继承 interrupt () , 要么注意调用父类的 interrupt () 函数,否则自己处
理信号。

 

class  MyService :  public  Ice::Service 
{
protected :
    
virtual   bool  start( int char   *  []);
    
virtual   bool  stop();
    
virtual   void  interrupt();
private :
    Ice::ObjectAdapterPtr m_adapter;
};

void  MyService::interrupt()
{
    std::cout 
<<   " Receive signal ... "   <<  std::endl;
    Ice::Service::interrupt();
}
bool  MyService::stop()
{
    std::cout 
<<   " Stop running ... "   <<  std::endl;
    
return   true ;
}
bool  MyService::start( int  argc,  char   *  argv[])
{
    std::
string  endpoint  =   " tcp -p 10000:udp -p 10000 " ;
    m_adapter 
=  communicator() -> createObjectAdapterWithEndpoints( " MonitorAdapter " , endpoint);

    Ice::ObjectPtr 
object   =   new  CCheckFile;
    m_adapter
-> add( object ,communicator() -> stringToIdentity( " CheckFile " ));
    m_adapter
-> activate();
    
return   true ;
}

int  main( int  argc,  char *  argv[])
{
    MyService svc;
    
int  ret  =  svc.main(argc, argv);
    
return  ret;
}

 

五.作为后台服务 /daemon 运行

Ice::Service 提供的安装方式很简洁,这个功能也是 Ice::Service 的主要魅力所在。

  1) Unix 看守

Unix 平台上, Ice::Service 识别 以下命令行 选项

--daemon

指明程序 应该 看守运行。 涉及到 建一个后台子 程, Service::main 将在 个子 程中 行其任 。在子 程成功 start 函数之前,父 程不会 ( shell 脚本启动看守常常会带来不确定性,上述行为消除了这一不确定性,因为它确保了命令调用不会在看守准备好接收请求之前就完成 ) 。除非另外收到指示,否 Ice::Service 会把子 程的当前工作目 录变 根目 ,并关 所有无用的文件描述符。注意, 在通信器初始化之前,各文件描述符不会关 ,也就是 ,在 时间 里, 入、 出,以及 错误 都可以使用。 例如, IceSSL 插件可能需要在 入上 提示 入口令,而如果 置了 Ice.PrintProcessId Ice 可能要在 出上打印子 id

--noclose

阻止 Ice::Service 无用的文件描述符。 调试 程中, 可能会很有用,因 这样 一来,你就可以通 看守的 出和 错误进 出了。

--nochdir

阻止 Ice::Service 更当前工作目 --noclose --nochdir 选项 只能和 --daemon 一起指定。在 传给 start 函数的参数向量中, 选项 会被移除。

2) Win32 服务

Win32 平台上 2 ,如果指定了 --service 选项 Ice::Service 会把 用作 Windows ( Windows 95/98/ME 上不支持 Windows 服务 )

--service NAME

名叫 NAME Windows 传给 start 函数的参数向量中, 选项 会被移除。
但是,在 用作 Windows 运行之前,它必 先被安装,因此 Ice::Service 类还 支持另外一些的命令行 选项 ,用于 行管理活

--install NAME [--display DISP] [--executable EXEC][ARG ...]
安装 NAME 如果指定了 --display 选项 ,就把 DISP 用作服 示名,否 就使用 NAME 。如果指定了 --executable 选项 ,就把 EXEC 用作服 的可 行路径名,否 就使用可 行文件的路径名来 --install 其他任何参数都会不加改 传给 Service::start 函数。注意,在启 动时传给 的参数集中, 个命令会自 增加命令行参数 --service NAME ,因此,你不需要 式地指定 选项

--uninstall NAME
移除 NAME 如果服 目前是活 的,在反安装之前,必 先使它停止。

--start NAME [ARG ...]
NAME 。其他任何参数都会不加改 传给 Service::start 函数。     

--stop NAME
停止 NAME 。如果指定的管理命令不止一个,或者在使用 --service 的同 时还 使用了管理命令 ,就会 错误 。在 行了管理命令之后,程序会立即 止。 Ice::Service 支持 Windows 控制代 SERVICE_CONTROL_INTERROGATE SERVICE_CONTROL_STOP 。在收到 SERVICE_CONTROL_STOP , Ice::Service shutdown 函数。
 

六.代码分析

分析 run 函数和信号处理函数 handleInterrupt

1. run 函数

int  Ice::Service::run( int &  argc,  char *  argv[],  const  InitializationData &  initData)
{
    
//  run()被main()函数调用,在main()函数中解析用户参数并决定运行模式
    
//  决定在后台运行
     if (_service)
    {
#ifdef _WIN32
        
return  runService(argc, argv, initData);
#else
        
return  runDaemon(argc, argv, initData);
#endif
    }

    
//  在前台运行
     int  status  =  EXIT_FAILURE;
    
try
    {
        
//  设置信号捕捉器,其作用实现在对Application的分析文章中描述
        _ctrlCHandler  =   new  IceUtil::CtrlCHandler;

        
//
        
//  初始化Ice通信器, 注意这里你可以通过改写initializeCommunicator()
        
//  来控制Ice通信器的生成
        _communicator  =  initializeCommunicator(argc, argv, initData);

        
//  有关log的设定
        _logger  =  _communicator -> getLogger();

        
//  从配置读取Ice.Nohup,默认值为1。决定是否要忽略SIGHUP消息.
//  使得应用在用户注销或者shell退出后依然运行
        _nohup  =  _communicator -> getProperties() -> getPropertyAsIntWithDefault( " Ice.Nohup " 1 >   0 ;

        
//  执行用户的主体函数
         if (start(argc, argv))
        {
            
//  等待应用结束,注意Ice::Application不会等待结束。
            waitForShutdown();

            
//  调用用户的清理函数
             if (stop())
            {
                status 
=  EXIT_SUCCESS;
            }
        }
    }
    
catch ( const  IceUtil::Exception &  ex)
    {
        ostringstream ostr;
        ostr 
<<   " service caught unhandled Ice exception: "   <<  ex;
        error(ostr.str());
    }
    
catch ( const  std::exception &  ex)
    {
        ostringstream ostr;
        ostr 
<<   " service caught unhandled std::exception: "   <<  ex.what();
        error(ostr.str());
    }
    
catch ( const  std:: string &  msg)
    {
        ostringstream ostr;
        ostr 
<<   " service caught unhandled exception: "   <<  msg;
        error(ostr.str());
    }
    
catch ( const   char *  msg)
    {
        ostringstream ostr;
        ostr 
<<   " service caught unhandled exception: "   <<  msg;
        error(ostr.str());
    }
    
catch (...)
    {
        error(
" service caught unhandled C++ exception " );
    }

    
try
    {
        _communicator
-> destroy();
    }
    
catch (...)
    {
    }

    
return  status;
}

 2. handleInterrupt () 函数

void  Ice::Service::handleInterrupt( int  sig)
{
#ifdef _WIN32
    
//  如果设置了Ice.Nohup,则忽略用户注销消息
     if (_nohup  &&  sig  ==  CTRL_LOGOFF_EVENT)
    {
        
return ;
    }
#else
    
//  如果设置了Ice.Nohup,则忽略shell退出/用户注销消息
     if (_nohup  &&  sig  ==  SIGHUP)
    {
        
return ;
    }
#endif
    
//  调用信号回调函数
    interrupt();
}

 

注意, interrupt () 的默认实现是调用 shutdown() ,也就是关闭 Service 。因此默认情况下, Ctrl+C 就可以正常退出。

七.参考文献
Ice-1.3.0 中文手册(马维达,感谢他的无私贡献)
Ice-3.1.1 英文手册
Ice-3.2.1 源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值