<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    Ice筆記-利用Ice::Application類簡化Ice應用

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    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(intchar*[]);
    int main(intchar*[], const char*);
    int main(intchar*[], const Ice::InitializationData&);
    int main(intchar*[], 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(intchar*[]) = 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的代碼如下:

     


    RFID設備管理軟件#include <Ice/Ice.h>
    RFID設備管理軟件
    class MyApplication : virtual public Ice::Application
    RFID設備管理軟件
    {
    RFID設備管理軟件
    public:
    RFID設備管理軟件       
    virtual int run(intchar * []) {
    RFID設備管理軟件
    RFID設備管理軟件       
    // 如果需要,設置信號回調模式
    RFID設備管理軟件
                  interruptCallback();
    RFID設備管理軟件              
    // ignoreInterrupt();
    RFID設備管理軟件
    RFID設備管理軟件              
    // Add Server code here...
    RFID設備管理軟件              
    // ...
    RFID設備管理軟件

    RFID設備管理軟件              
    return 0;
    RFID設備管理軟件       }

    RFID設備管理軟件     
    RFID設備管理軟件      
    virtual void interruptCallback(int{
    RFID設備管理軟件             cout 
    << appName() << “ receive signal ” << endl;
    RFID設備管理軟件      }

    RFID設備管理軟件}
    ;
    RFID設備管理軟件
    RFID設備管理軟件
    int main(int argc, char * argv[])
    RFID設備管理軟件
    {
    RFID設備管理軟件
    RFID設備管理軟件       MyApplication app;
    RFID設備管理軟件       
    return app.main(argc, argv);
    RFID設備管理軟件}
    可以看出,繁瑣的初始化細節已經不用考慮。抽象層次也更清晰一些。

    四.實現分析

    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源碼

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全