ICE 的回調

                                   ICE 的回調

   使用分佈式計算中間件ICE到現在已經有一年多了,在這一年裏裏面對ICE的理解、應用比較熟悉。

   使用ICE寫分佈式軟件,確實是很方便:ICE比較穩定、可靠,調用返回速度低延遲,使用簡單,學習曲線不是很陡。

    總之利用ICE開發分佈式軟件,是一個可行的選擇。

    在實際的過程中,ICE客戶端跟服務端的數據流動是單項的,也就是客戶端獲取服務端的一個代理,從而與服務端進行數據交互,如果服務端要主動給客戶端數據的時候,則需要我們給服務端傳去一個客戶端的代理。這時客戶端也是一個服務器。在ICE中客戶端、服務端沒有嚴格的限制。

    在ICE中有三種提供回調的方法,以下將具體介紹這三種方法:

    1:適合服務器、客戶端在如下的環境。客戶和服務器程序或者運行在同一個主機上,或者運行在沒有網絡限制的多個主機上。這樣的環境下,提供回調是最簡單的。

     以下是簡單的例子,首先先寫slice文件:

 // **********************************************************************
//
// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
//
// This copy of Ice is licensed to you under the terms described in the
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************
#ifndef CALLBACK_ICE
#define CALLBACK_ICE
module Demo
{
interface CallbackReceiver
{
    void callback();
};
interface CallbackSender
{
    void initiateCallback(CallbackReceiver* proxy);
    void shutdown();
};
};
#endif

這個例子直接從ICE提供的demo中獲得的。

然後利用ICE提供的slice2cpp程序,生成骨架代碼,具體就不說了。

接着客服端實現利用如下的方式,提供回調代理:

CallbackSenderPrx senderPrx =

CallbackSenderPrx::checkedCast( communicator()->propertyToProxy("Callback.CallbackServer"))

"Callback.CallbackServer"是通過配置文件配置的,該代碼是利用繼承Ice::Application,重載它的main成員函數。communicator是ICE提供的通信器。

以下,是客戶端提供回調的形式化代碼:

Ice::ObjectAdapterPtr adapter = communicator()->createObjectAdapter("Callback.Client");
adapter->add(new CallbackReceiverI, communicator()->stringToIdentity("callbackReceiver"));
adapter->activate();

CallbackReceiverPrx twowayR = CallbackReceiverPrx::uncheckedCast(
 adapter->createProxy(communicator()->stringToIdentity("callbackReceiver")));

然後調用:

senderPrx ->initiateCallback(twowayR);

這樣就把客戶端的一個回調代理傳給服務端。

不過這樣的傳回調在比較負責的網絡環境下,回調是會失敗的。在實際的開發過程中,我就遇到這樣的問題。然後去文檔中尋求,解決方法。

我遇到的問題,在文檔中Glacier有介紹,客戶端和服務端的網絡環境如圖:


 

在這樣的情況下,ICE回調給客戶端是失敗的,原因是ICE通過那個回調對象,不能找到客戶端的路由信息。

因此有兩種可選的方式,一種是利用Glacier,另外一種Bidirectional Connections(可能是要ICE3.2.0及其以後的版本才支持)。

  我在實際的過程中,是利用Bidirectional Connections解決了上面的那個問題,是通過了實際的測試。Glacier方法,我沒實際測試過。

  因此,具體介紹Bidirectional Connections方法。在ICE文檔3.2.1中提到,如何使用這個方法,大家有興趣可以去看看。

  下面提供一些形式化的代碼,並說明注意事項。

   還是先把slice文件(來自ICE DEMO)提供出來,以下是slice文件:

   // **********************************************************************
//
// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
//
// This copy of Ice is licensed to you under the terms described in the
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************
#ifndef CALLBACK_ICE
#define CALLBACK_ICE
#include <Ice/Identity.ice>
module Demo
{
interface CallbackReceiver
{
    void callback(int num);
};
interface CallbackSender
{
    void addClient(Ice::Identity ident);
};
};
#endif

客戶端的形式化代碼:

   CallbackSenderPrx server =
        CallbackSenderPrx::checkedCast(communicator()->propertyToProxy  

        ("Callback.Client.CallbackServer"));

    Ice::ObjectAdapterPtr adapter = communicator()->createObjectAdapter("");
    Ice::Identity ident;
    ident.name = IceUtil::generateUUID();
    ident.category = "";
    adapter->add(new CallbackReceiverI, ident);
    adapter->activate();
    server->ice_getConnection()->setAdapter(adapter);
    server->addClient(ident);

服務端的形式化代碼:

    CallbackReceiverPrx client = CallbackReceiverPrx::uncheckedCast(current.con->createProxy(ident));

     使用這個方式的一個注意事項:

1:在配置文件

#
# ACM must be disabled for bidirectional connections
#
Ice.ACM.Client=0

要將Ice.ACM.Client屬性禁用掉。如果回調對象被關閉的話,只能重新

    if(server->ice_getConnection()->getAdapter() == NULL)

         server->ice_getConnection()->setAdapter(adapter);
    server->addClient(ident);

因爲ICE有一個機制如果在一定的時間內,沒有發生數據交互,連接會被關閉

   其實也可以利用一個hook線程對回調代理進行ice_ping()。

2:利用Bidirectional Connections,這樣的代理是在原來的連接基礎上建立起來的。因此不能修改回調代理的安全、超時等屬性。

  以上是我在實際開發過程中,獲得的經驗,希望對大家有幫助。

 

 

發佈了49 篇原創文章 · 獲贊 24 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章