利用Ice::Application类简化Ice应用
在编写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无真正成员变量,其实际使用变量均在实现文件中以静态形式提供。因此其提供的主要是静态接口
1 // Application的入口函数,提供了丰富的初始化方式,一般使用第一个
2 // 将应用主函数参数直接传入即可
3 int main(int, char*[]);
4 int main(int, char*[], const char*);
5 int main(int, char*[], const Ice::InitializationData&);
6 int main(int, char*[], const char*, const Ice::LoggerPtr&);
7 int main(const StringSeq&);
8 int main(const StringSeq&, const char*);
9 int main(const StringSeq&, const Ice::InitializationData&);
10
11 // 应用的执行循环,应用需要继承这个函数并用自己的逻辑重写
12 virtual int run(int, char*[]) = 0;
13
14 // 信号回调函数
15 // 如果需要自己对信号进行处理,则需要继承和改写这个函数
16 // 注意,需在run()函数中调用callbackOnInterrupt()来向Ice表示使用用户回调
17 // 该函数的默认实现是空函数
18 virtual void interruptCallback(int);
19
20 // 返回应用名,即argv[0]
21 static const char* appName();
22
23 // 返回当前使用的Ice通信器实例指针
24 static CommunicatorPtr communicator();
25
26 // 设置信号处理模式
27 //
28 // 销毁模式:信号到来时将通信器实例销毁,也是Application的默认模式
29 static void destroyOnInterrupt();
30
31 // 关闭模式:信号到来时将通信器实例关闭,但不销毁
32 static void shutdownOnInterrupt();
33
34 // 忽略模式:信号到来时将通信器不做任何处理
35 static void ignoreInterrupt();
36
37 // 用户模式:信号到来时将调用interruptCallback()函数
38 static void callbackOnInterrupt();
39
40 // 信号的阻止和放开,不常用
41 // 阻塞信号的到来
42 static void holdInterrupt();
43
44 // 放开被阻塞的信号
45 static void releaseInterrupt();
46
47 // Application当前是否被信号中断
48 // 可用于判断Application的结束是否由于信号造成
49 static bool interrupted();
三.使用方法
一般直接初始化通信器的用法如下:
1 #include <Ice/Ice.h>
2 int main(int argc, char * argv[])
3 {
4 int status = 0;
5 Ice::CommunicatorPtr ic;
6 try {
7 ic = Ice::initialize(argc, argv);
8
9 // Server code here...
10
11 // ...
12
13 } catch (const Ice::Exception & e) {
14 cerr << e << endl;
15 status = 1;
16 }
17
18 if (ic)
19 ic->destroy();
20 return status;
21 }
使用Ice::Application的代码如下:
1 #include <Ice/Ice.h>
2 class MyApplication : virtual public Ice::Application
3 {
4 public:
5 virtual int run(int, char * []) {
6
7 // 如果需要,设置信号回调模式
8 interruptCallback();
9 // ignoreInterrupt();
10
11 // Add Server code here...
12 // ...
13
14 return 0;
15 }
16
17 virtual void interruptCallback(int) {
18 cout << appName() << “ receive signal ” << endl;
19 }
20 };
21
22 int main(int argc, char * argv[])
23 {
24
25 MyApplication app;
26 return app.main(argc, argv);
27 }
可以看出,繁琐的初始化细节已经不用考虑。抽象层次也更清晰一些。
四.实现分析
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&。
函数代码如下:
1 int
2 Ice::Application::main(int argc, char* argv[], const InitializationData& initData)
3 {
4 // 不允许重复调用
5 if(_communicator != 0)
6 {
7 cerr << argv[0] << ": only one instance of the Application class can be used" << endl;
8 return EXIT_FAILURE;
9 }
10 int status;
11
12 try
13 {
14 // 设置信号捕捉器
15 CtrlCHandler ctrCHandler;
16 _ctrlCHandler = &ctrCHandler;
17
18 try
19 { // 内部使用的条件变量初始化,主要用于信号阻塞
20 if(_condVar.get() == 0)
21 {
22 _condVar.reset(new Cond);
23 }
24
25 // 初始化Ice通信器及其它变量(均为静态变量)
26 _interrupted = false;
27 _appName = argv[0]; // 设置应用名
28
29 _application = this;
30 _communicator = initialize(argc, argv, initData);
31 _destroyed = false;
32
33 // 判断应用是否提供了Ice.Nohup参数
34 // 如果Ice.Nohup大于0, Application会忽略SIGHUP(UNIX) 和
35 // CTRL_LOGOFF_EVENT (Windows). 因此,如果启动应用的用户注销,
36 // 设置了Ice.Nohup 的应用能继续运行(只适用于C++)。
37 _nohup = (_communicator->getProperties()->getPropertyAsInt("Ice.Nohup") > 0);
38
39 // 收到信号的默认处理方式是销毁通信器
40 destroyOnInterrupt();
41 status = run(argc, argv);
42 }
43 catch(const IceUtil::Exception& ex)
44 {
45 cerr << _appName << ": " << ex << endl;
46 status = EXIT_FAILURE;
47 }
48 catch(const std::exception& ex)
49 {
50 cerr << _appName << ": std::exception: " << ex.what() << endl;
51 status = EXIT_FAILURE;
52 }
53 catch(const std::string& msg)
54 {
55 cerr << _appName << ": " << msg << endl;
56 status = EXIT_FAILURE;
57 }
58 catch(const char* msg)
59 {
60 cerr << _appName << ": " << msg << endl;
61 status = EXIT_FAILURE;
62 }
63 catch(...)
64 {
65 cerr << _appName << ": unknown exception" << endl;
66 status = EXIT_FAILURE;
67 }
68
69 // Application清理时,需要忽略所有信号
70 ignoreInterrupt();
71 {
72 StaticMutex::Lock lock(_mutex);
73 while(_callbackInProgress)
74 {
75 _condVar->wait(lock);
76 }
77 if(_destroyed)
78 {
79 _communicator = 0;
80 }
81 else
82 {
83 _destroyed = true;
84 //
85 // And _communicator != 0, meaning will be destroyed
86 // next, _destroyed = true also ensures that any
87 // remaining callback won't do anything
88 //
89 }
90 _application = 0;
91 }
92
93 // 清理通信器(如果没有通过信号清理过)
94 if(_communicator != 0)
95 {
96 try
97 {
98 _communicator->destroy();
99 }
100 catch(const IceUtil::Exception& ex)
101 {
102 cerr << _appName << ": " << ex << endl;
103 status = EXIT_FAILURE;
104 }
105 catch(const std::exception& ex)
106 {
107 cerr << _appName << ": std::exception: " << ex.what() << endl;
108 status = EXIT_FAILURE;
109 }
110 catch(...)
111 {
112 cerr << _appName << ": unknown exception" << endl;
113 status = EXIT_FAILURE;
114 }
115 _communicator = 0;
116 }
117
118 //
119 // Set _ctrlCHandler to 0 only once communicator->destroy() has completed.
120 //
121 _ctrlCHandler = 0;
122 }
123 catch(const CtrlCHandlerException&)
124 {
125 cerr << argv[0] << ": only one instance of the Application class can be used" << endl;
126 status = EXIT_FAILURE;
127 }
128
129 return status;
130 }
上一篇的 hello world,我们看到 main() 中有那些繁琐的 try ... catch ...,每次都写,很麻烦。
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::Application本身是一个抽象类,其run()函数为纯虚函数,因此必须被继承后使用。
Ice::Application 是一个单体(singleton)类,会创建单个通信器。如果你要使用多个通信器,不能使用Ice::Application来定义多个App。而至多定义一个App的实例。
其它通信器需要使用Ice::initialize()手工生成。
一般而 言,Ice::Application 类对于Ice 客户和服务器来说已经非常方便,但在有些情况下,应用可能需要作为Unix 看守(daemon)或Win32 服务运行在系统一级。对于这样的情况,Ice 提供了Ice::Service。一个可与Ice::Application 相比的单体类,但它还封装了低级的、 针对特定平台的初始化和关闭步骤――系统服务常常需要使用这样的步骤。
http://www.cnblogs.com/liwei81730/archive/2011/07/09/2101844.html
http://blog.csdn.net/ydogg/article/category/340307

浙公网安备 33010602011771号