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无真正成员变量,其实际使用变量均在实现文件中以静态形式提供。因此其提供的主要是静态接口
三.使用方法
一般直接初始化通信器的用法如下:
{ 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;
}
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
四.实现分析
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&。
函数代码如下:
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源码