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

简介: Ice笔记-利用Ice::Application类简化Ice应用 作者:ydogg,转载请申明。  在编写Ice相关应用时,无论是Client还是Server端,都必须进行一些必要的动作,如: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(intchar * []) {

       
// 如果需要,设置信号回调模式
              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_EVENTCTRL_BREAK_EVENT、CTRL_CLOSE_EVENTCTRL_LOGOFF_EVENT以及CTRL_SHUTDOWN_EVENT信号。

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

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

目录
相关文章
|
网络协议 网络安全 网络虚拟化
IPv6地址详解
IPv4地址资源的紧张限制了Internet的进一步发展。NAT、CIDR、VLSM等技术的使用仅仅暂时缓解IPv4地址紧张,但不是根本解决办法。
872 0
|
10月前
|
机器学习/深度学习 运维 监控
基于特征子空间的高维异常检测:一种高效且可解释的方法
本文探讨了一种替代传统单一检测器的方法,通过构建多个专注于特征子集(子空间)的检测器系统,来提高异常检测的准确性和效率。文章详细介绍了子空间方法在处理高维数据时的优势,包括缓解维度灾难、提高异常检测的可解释性和计算效率。同时,文中还讨论了子空间的选择策略,如基于领域知识、相关性、随机选择等,并介绍了PyOD工具包中实现子空间异常检测的具体方法。通过这些技术,异常检测系统能够更有效地识别数据中的异常记录,尤其是在特征数量众多的情况下。
287 9
基于特征子空间的高维异常检测:一种高效且可解释的方法
|
10月前
|
前端开发 UED 开发者
React 表格组件设计
本文介绍了 React 表格组件的设计,涵盖基本表格、虚拟滚动表格、可编辑表格和响应式表格。详细探讨了常见问题、易错点及解决方法,并提供了代码示例,帮助开发者提升表格组件的性能和用户体验。
374 5
|
数据采集 监控 大数据
大数据时代的数据质量与数据治理策略
在大数据时代,高质量数据对驱动企业决策和创新至关重要。然而,数据量的爆炸式增长带来了数据质量挑战,如准确性、完整性和时效性问题。本文探讨了数据质量的定义、重要性及评估方法,并提出数据治理策略,包括建立治理体系、数据质量管理流程和生命周期管理。通过使用Apache Nifi等工具进行数据质量监控和问题修复,结合元数据管理和数据集成工具,企业可以提升数据质量,释放数据价值。数据治理需要全员参与和持续优化,以应对数据质量挑战并推动企业发展。
2886 3
|
SQL 关系型数据库 MySQL
mysql密码错误-ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using passwor:yes)
这篇文章提供了解决MySQL数据库"Access denied for user 'root'@'localhost' (using password: YES)"错误的方法,通过跳过密码验证、修改root密码,然后重启服务来解决登录问题。
mysql密码错误-ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using passwor:yes)
|
敏捷开发 BI 测试技术
阿里云云效产品使用问题之遇到“主机无法连接”该怎么办
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
C语言
C 语言 math.h 库介绍
C 语言 math.h 库介绍
228 0
|
存储 关系型数据库 MySQL
TiDB与MySQL、PostgreSQL等数据库的比较分析
【2月更文挑战第25天】本文将对TiDB、MySQL和PostgreSQL等数据库进行详细的比较分析,探讨它们各自的优势和劣势。TiDB作为一款分布式关系型数据库,在扩展性、并发性能等方面表现突出;MySQL以其易用性和成熟性受到广泛应用;PostgreSQL则在数据完整性、扩展性等方面具有优势。通过对比这些数据库的特点和适用场景,帮助企业更好地选择适合自己业务需求的数据库系统。
2143 4
|
缓存 JSON Java
京东零售 / hotkey 热点key探测工具使用
京东零售 / hotkey 热点key探测工具使用
302 0
Qt在线安装时出现网络错误的解决办法(Windows)
Qt在线安装时出现网络错误的解决办法(Windows)