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

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

作者:ydogg,转载请申明。

 在编写Ice相关应用时,无论是Client还是Server端,都必须进行一些必要的动作,如:Ice通信器初始化、异常捕获,以及应用终止后的销毁。鉴于每个应用都需要,Ice运行时库提供了Ice::Application类来解放用户,避免重复劳动,消除繁琐的初始化和销毁细节。Ice::Application虽然实用,但总体来说是个比较简单的类,主要提供了Ice通信器初始化和信号捕获处理两大功能。下面将从功能和实现两方面进行阐述,并给出常见用法和注意事项。源码版本为Ice-3.2.1。

 一.Ice::Application概述

Ice::Application本身是一个抽象类,其run()函数为纯虚函数,因此必须被继承后使用。Ice::Application 是一个单体(singleton)类,会创建单个通信器。 如果你要使用多个通信器,不能使用Ice::Application来定义多个App。而至多定义一个App的实例。
其它通信器需要使用Ice::initialize()手工生成。

 二.Ice::Application的成员

Ice::Application无真正成员变量,其实际使用变量均在实现文件中以静态形式提供。因此其提供的主要是静态接口 

//  Application的入口函数,提供了丰富的初始化方式,一般使用第一个 //  将应用主函数参数直接传入即可 int  main( int ,  char * []); int  main( int ,  char * [],  const  char * ); int  main( int ,  char * [],  const  Ice::InitializationData & ); int  main( int ,  char * [],  const  char * ,  const  Ice::LoggerPtr & ); int  main( const  StringSeq & ); int  main( const  StringSeq & ,  const  char * ); int  main( const  StringSeq & ,  const  Ice::InitializationData & ); //  应用的执行循环,应用需要继承这个函数并用自己的逻辑重写 virtual  int  run( int ,  char * [])  =  0 ; //  信号回调函数 //  如果需要自己对信号进行处理,则需要继承和改写这个函数 //  注意,需在run()函数中调用callbackOnInterrupt()来向Ice表示使用用户回调 //  该函数的默认实现是空函数 virtual  void  interruptCallback( int ); //  返回应用名,即argv[0] static  const  char *  appName(); //  返回当前使用的Ice通信器实例指针 static  CommunicatorPtr communicator(); //  设置信号处理模式 // //  销毁模式:信号到来时将通信器实例销毁,也是Application的默认模式 static  void  destroyOnInterrupt(); //  关闭模式:信号到来时将通信器实例关闭,但不销毁 static  void  shutdownOnInterrupt(); //  忽略模式:信号到来时将通信器不做任何处理 static  void  ignoreInterrupt(); //  用户模式:信号到来时将调用interruptCallback()函数 static  void  callbackOnInterrupt(); //  信号的阻止和放开,不常用 //  阻塞信号的到来 static  void  holdInterrupt(); //  放开被阻塞的信号 static  void  releaseInterrupt(); //  Application当前是否被信号中断 //  可用于判断Application的结束是否由于信号造成 static  bool  interrupted();

三.使用方法

一般直接初始化通信器的用法如下:

#include  < Ice / Ice.h > int  main( int  argc,  char  *  argv[])
{ int  status  =  0 ;
       Ice::CommunicatorPtr ic; try  {
              ic  =  Ice::initialize(argc, argv); //  Server code here... //  ...
        }  catch  ( const  Ice::Exception  &  e) {
              cerr  <<  e  <<  endl;
              status  =  1 ;
       } if  (ic)
              ic -> destroy(); return  status;
}
  使用 Ice::Application 的代码如下:
#include  < Ice / Ice.h >
class  MyApplication :  virtual  public  Ice::Application
{
public:
       
virtual int run(int, char * []) {
       
// 如果需要,设置信号回调模式
              interruptCallback();
              
// ignoreInterrupt();
              
// Add Server code here...
              
// ...
              
return 0;
       }
     
      
virtual void interruptCallback(int) {
             cout 
<< appName() << “ receive signal ” << endl;
      }
}
;
int  main( int  argc,  char  *  argv[])
{
       MyApplication app;
       
return app.main(argc, argv);
}
可以看出,繁琐的初始化细节已经不用考虑。抽象层次也更清晰一些。

四.实现分析

main的实现较多,但都是对函数int main(int, char*[], const Ice::InitializationData&)的再包装,其行为
如下:

①        创建一个IceUtil::CtrlCHandler,适当地关闭通信器。

②        保存传入的argv[0]参数。以便通过静态的appName 成员函数,提供应用的名字。

③        初始化(通过调用Ice::initialize)。通过调用静态的communicator()成员,可以访问当前使用的通信器。

④        扫描参数向量,查找与Ice run time 有关的选项,并移除这样的选项。因此,在传给你的run 方法的参数向量中,不再有与Ice 有关的选项,而只有针对你的应用的选项和参数。
实际上,3,4步骤都由同一个函数Ice::initialize来完成。

⑤        调用run()函数

⑥        销毁通信器(如果正常结束,没有收到终止信号)

 在以上过程中,main()函数还捕获了几乎全部异常,包括IceUtil::Exception,std::exception,甚至还有const char*和const string&。

函数代码如下:

int
Ice::Application::main( int  argc,  char *  argv[],  const  InitializationData &  initData)
{ //  不允许重复调用      if (_communicator  !=  0 )
    {
        cerr  <<  argv[ 0 ]  <<  " : only one instance of the Application class can be used "  <<  endl; return  EXIT_FAILURE;
    } int  status; try
    { //  设置信号捕捉器          CtrlCHandler ctrCHandler;
        _ctrlCHandler  =  & ctrCHandler; try
        {    //  内部使用的条件变量初始化,主要用于信号阻塞              if (_condVar. get ()  ==  0 )
            {
                _condVar.reset( new  Cond);
            } //  初始化Ice通信器及其它变量(均为静态变量)             _interrupted  =  false ;
            _appName  =  argv[ 0 ];     //  设置应用名                 
            _application  =  this ;
            _communicator  =  initialize(argc, argv, initData);
            _destroyed  =  false ; //  判断应用是否提供了Ice.Nohup参数 //  如果Ice.Nohup大于0, Application会忽略SIGHUP(UNIX) 和  
           //  CTRL_LOGOFF_EVENT (Windows).  因此,如果启动应用的用户注销,
           // 设置了Ice.Nohup 的应用能继续运行(只 适用于C++)。              _nohup  =  (_communicator -> getProperties() -> getPropertyAsInt( " Ice.Nohup " )  >  0 ); //  收到信号的默认处理方式是销毁通信器             destroyOnInterrupt();
            status  =  run(argc, argv);
        } catch ( const  IceUtil::Exception &  ex)
        {
            cerr  <<  _appName  <<  " :  "  <<  ex  <<  endl;
            status  =  EXIT_FAILURE;
        } catch ( const  std::exception &  ex)
        {
            cerr  <<  _appName  <<  " : std::exception:  "  <<  ex.what()  <<  endl;
            status  =  EXIT_FAILURE;
        } catch ( const  std:: string &  msg)
        {
            cerr  <<  _appName  <<  " :  "  <<  msg  <<  endl;
            status  =  EXIT_FAILURE;
        } catch ( const  char *  msg)
        {
            cerr  <<  _appName  <<  " :  "  <<  msg  <<  endl;
            status  =  EXIT_FAILURE;
        } catch (...)
        {
            cerr  <<  _appName  <<  " : unknown exception "  <<  endl;
            status  =  EXIT_FAILURE;
        } //  Application清理时,需要忽略所有信号        ignoreInterrupt();
        {
            StaticMutex::Lock  lock (_mutex); while (_callbackInProgress)
            {
                _condVar -> wait( lock );
            } if (_destroyed)
            {
                _communicator  =  0 ;
            } else
            {
                _destroyed  =  true ; // //  And _communicator != 0, meaning will be destroyed //  next, _destroyed = true also ensures that any //  remaining callback won't do anything //             }
            _application  =  0 ;
        } //  清理通信器(如果没有通过信号清理过)          if (_communicator  !=  0 )
        {   try
            {
                _communicator -> destroy();
            } catch ( const  IceUtil::Exception &  ex)
            {
                cerr  <<  _appName  <<  " :  "  <<  ex  <<  endl;
                status  =  EXIT_FAILURE;
            } catch ( const  std::exception &  ex)
            {
                cerr  <<  _appName  <<  " : std::exception:  "  <<  ex.what()  <<  endl;
                status  =  EXIT_FAILURE;
            } catch (...)
            {
                cerr  <<  _appName  <<  " : unknown exception "  <<  endl;
                status  =  EXIT_FAILURE;
            }
            _communicator  =  0 ;
        } // //  Set _ctrlCHandler to 0 only once communicator->destroy() has completed. //          _ctrlCHandler  =  0 ;
    } catch ( const  CtrlCHandlerException & )
    {
        cerr  <<  argv[ 0 ]  <<  " : only one instance of the Application class can be used "  <<  endl;
        status  =  EXIT_FAILURE;
    } return  status;
}

IceUtil::CtrlCHandler的实现在IceUtil/CtrlCHandler.cpp中,其在windows下使用SetConsoleCtrlHandler()方式实现,可捕获CTRL_C_EVENT、CTRL_BREAK_EVENT、CTRL_CLOSE_EVENT、CTRL_LOGOFF_EVENT以及CTRL_SHUTDOWN_EVENT信号。

在linux下,通过pthread_sigmask()和sigwait()配合实现,注意实现中使用了一个内部的独立线程对信号进行捕获。其选择捕获的信号有SIGHUP、SIGINT、SIGTERM。其它Ice::Application的信号模式设置函数都是利用它来挂接自己的处理函数,来做出不同的动作。在此不再细述,请参见源码。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值