ICE簡單介紹及使用示例


轉自:http://blog.csdn.net/zhu2695/article/details/51494664

 

1、ICE是什么? 
ICE是ZEROC的開源通信協議產品,它的全稱是:The Internet Communications Engine,翻譯為中文是互聯網通信引擎,是一個面向對象的中間件,使我們能夠以最小的代價構建分布式應用程序。ICE使我們專注於應用邏輯的開發,它來處理所有底層的網絡接口編程,這樣我們就不用去考慮這樣的細節:打開網絡連接、網絡數據傳輸的序列化與反序列化、連接失敗的嘗試次數等。 
2、為什么會有ICE? 
ICE是分布式應用的一種比較好的解決方案,雖然現在也有一些比較流行的分布式應用解決方案,如微軟的.NET(以及原來的DCOM)、CORBA及WEB SERVICE等,但是這些面向對象的中間件都存在一些不足: 
.NET是微軟產品,只面向WINDOWS系統,而實際的情況是在當前的網絡環境下,不同的計算機會運行不同的系統,如LINUX上面就不可能使用.NET; 
CORBA雖然在統一標准方面做了很多的工作,但是不同的供應商實現之間還是缺乏互操作性,並且目前還沒有一家供應商可以針對所有的異種環境提供所有的實現支持,且CORBA的實現比較復雜,學習及實施的成本都會比較高; 
WEB SERVICE最要命的缺點就是他的性能問題,對於要求比較高的行業是很少會考慮WEB SERVICE的。 
ICE的產生就是源於.NET、CORBA及WEB SERVICE這些中間件的不足,它可以支持不同的系統,如WINDOWS、LINUX等,也可以支持在多種開發語言上使用,如C++、C、JAVA、RUBY、PYTHON、VB等,服務端可以是上面提到的任何一種語言實現的,客戶端也可以根據自己的實際情況選擇不同的語言實現,如服務端采用C語言實現,而客戶端采用JAVA語言實現,底層的通訊邏輯通過ICE的封裝實現,我們只需要關注業務邏輯。 
3、ICE是如何工作的? 
Ice 是一種面向對象的中間件平台,這意味着 Ice為構建面向對象的客戶-服務器應用提供了工具、API 和庫支持。要與Ice持有的對象進行通信,客戶端必須持有這個對象的代理(與CORBA的引用是相同的意思),這里的代理指的是這個對象的實例,ICE在運行時會定位到這個對象,然后尋找或激活它,再把In參數傳給遠程對象,再通過Out參數獲取返回結果。 
這里提到的代理又分為直接代理和間接代理,直接代理其內部保存有某個對象的標識,以及它的服務器的運行地址;間接代理指的是其內部保存有某個對象的標識,以及對象適配器名(object adapter name),間接代理沒有包含尋址信息,為了正確地定位服務器,客戶端在運行時會使用代理內部的對象適配器名,將其傳給某個定位器服務,比如IcePack服務,然后,定位器會把適配器名當作關鍵字,在含有服務器地址的表中進行查找,把當前的服務器地址返回給客戶,客戶端 run time現在知道了怎樣聯系服務器,就會像平常一樣分派 (dispatch)客戶請求。 
ICE可以保證在任何的網絡環境或者操作系統下,成功的調用只有一次,它在運行時會盡力的定位到遠程服務器,在連接失敗的情況下會做嘗試性重復性連接,確實連不上的情況會給用戶以提示。 
客戶端在調用服務端的方法時,可以采取同步或異步的方式實現,同步調用就相當於調用自己本地的方法一樣,其它行為會被阻塞;異步調用是非常有用的調用方式,如服務端需要准備的數據來自於其它異步接口,這個時候客戶端就不需要等待,待服務端數據准備充份后,以消息的方式通知客戶端,服務端就可以去干其它的事情了,而客戶端也可以到服務端獲取數據了。 
4、ICE調用模式 
ICE采用的網絡協議有TCP、UDP以及SSL三 種,不同於WebService,ICE在調用模式上有好幾種選擇方案,並且每種方案正對不同的網絡協議的特性做了相應的選擇。 
Oneway(單向調用):客戶端只需將調用注冊到本地傳輸緩沖區(Local Transport Buffers)后就立即返回,不會等待調用結果的返回,不對調用結果負責。 
Twoway(雙向調用):最通用的模式,同步方法調用模式,只能用TCP或SSL協議。 
Datagram(數據報):類似於Oneway調用,不同的是 Datagram調用只能采用UDP協議而且只能調用無返回值和無輸出參數的方法。 
BatchOneway(批量單向調用):先將調用存 在調用緩沖區里面,到達一定限額后自動批量發送所有請求(也可手動刷除緩沖區)。 
BatchDatagram(批量數據報):與上類似。 
不同的調用模式其實對應着不動的業務,對於大部分的有返回值的或需要實時響應的方法,我們可能都采用Twoway方式調用,對於一些無需返回值或 者不依賴返回值的業務,我們可以用Oneway或者BatchOneway方式,例如消息通知;剩下的Datagram和BatchDatagram方式 一般用在無返回值且不做可靠性檢查的業務上,例如日志。 
5、客戶端與服務端的結構 
 
這個圖示顯示了使用ICE做為中間件平台,客戶端及服務端的應用都是由應用代碼及ICE的庫代碼混合組成的。 
客戶應用及服務器應用分別對應用的是客戶端與服務端。 
代理是根據SLICE定義的ice文件實現,它提供了一個向下調用的接口,提供了數據的序列化與反序化。 
ICE的核心部份,提供了客戶端與服務端的網絡連接等核心通信功能,以及其它的網絡通信功能的實現及可能的問題的處理,讓我們在編寫應用代碼的時候不必要去關注這一塊,而專注於應用功能的實現。 
6. 要使用ICE,必須先安裝ICE,安裝及配置參考如下: 
WINDOWS:http://blog.csdn.net/fenglibing/archive/2011/04/28/6368665.aspx 
LINUX(BDB的安裝還有問題,無法使用SLICE2JAVA):http://blog.csdn.net/fenglibing/archive/2011/04/27/6367559.aspx 
這個示例是JAVA示例,是從ICE的幫助文檔中摘出來的,是一個輸出Hello World的測試程序,采用的ICE版本是3.1.1。1)、准備一個ice文件並命名為:Printer.ice,其內容為: 

    module Demo {  
    interface Printer {  
    void printString(string s);  
    };  
    };  
2)、轉到命令行,在Printer.ice文件保存目錄執行命令: 
  slice2java Printer.ice 
會在目錄下面生成一個Demo 文件夾,里面會生成一些JAVA文件,如下圖示: 
 
3)、這些文件的類圖結構如下: 
 
這里對生成的一些文件做些解釋,分兩兩部份,服務端類文件及客戶端類文件: 
• <interface-name>.java 
這個源文件聲明在ICE文件中定的接口名稱的Java接口,如這里是Printer。 
• _<interface-name>Operations.java 
_<interface-name>OperationsNC.java 
這是兩個定義操作的接口文件,每個接口文件中定義了一個操作實現,定義的操作與Slice接口中定義的操作相一致,只是在_<interface-name>Operations.java中定義的方法多了一個參數“Ice.Current __current”(注:Current對象的定義,請參見3.1.1版本文檔中的31.6 The Ice::Current Object說明),這個參數的作用是可以允許我們訪問 “正在執行的請求”和 “服務器中的操作的實現”等信息,也就是我們的請求需求需要其它請求的支持時或者要獲取其它請求的執行結果時,我們可以調用這個方法,這兩個接口文件都會被接口文件_<interface-name>.java繼承。 
•  _<interface-name>Disp.java 這個文件包含的是服務器端骨架類的定義,所用接口定義都要繼承這個東西,這里的接口指供客戶端調用的接口。 
• <interface-name>PrxHolder.java 代理定義holder 類,是對應Out參數使用的。一般參數都是值傳遞,這個類的作用是使參數通過引用傳遞。ICE框架應用了很多反射機制,這個類是改變遠程參數的一個映射。 
  • _<interface-name>Del.java 
  • _<interface-name>DelD.java 
  • _<interface-name>DelM.java 
不用關心上面的這些文件,這些文件包含的是供Java 映射內部使用的代碼;它們包含的功能與應用程序無關。 
• <interface-name>Prx.java 這個是代理接口。例如PrinterPrx,在客戶的地址空間中, PrinterPrx 的實例是“遠地的服務器中的Printer接口的實例”的“本地大使”。與服務器端對象有關的所有細節,比如其地址、所用協議、對象標識,都封裝在該實例中。 
注意, PrinterPrx 繼承自Ice.ObjectPrx。這反映了這樣一個事實:所有的Ice 接口都隱式地繼承自Ice::Object。 
說的更明白些,就是這個類的方法調用都是遠程服務端的調用,執行printString()方法的具體實現是在遠程服務端執行的。 
• <interface-name>PrxHelper.java 這個是接口的代理定義助手類,就是幫你獲得代理類的。經常用的就兩個方法checkedCast 和 uncheckedCast 。這兩個方法實現的都是向下轉換。 
注意, checkedCast 會聯系服務器。這是必要的,因為只有服務器情況中的代理實現確切地知道某個對象的類型。所以, checkedCast 可能會拋出ConnectTimeoutException 或ObjectNotExistException(這也解釋了為何需要助手類:ICE在運行時必須聯系服務器,所以我們不能使用Java 的向下轉換)。 
與此相反, uncheckedCast 不會聯系服務器,而是會無條件地返回具有所請求的類型的代理 。但是,如果你要使用uncheckedCast,你必須確定這個代理真的支持你想要轉換到的類型;而如果你弄錯了,你很可能會在調用代理上的操作時,引發運行時異常。對於這樣的類型失配,最后可能會引發OperationNotExistException,但也有可能引發其他異常,比如整編異常。而且,如果對象碰巧有一個同名的操作,但參數類型不同,則有可能根本不產生異常,你最后就會把調用發送給類型錯誤的對象;這個對象可能會做出非常糟糕的事情。 
4)、建立一個ECLIPSE工程,將生成的文件拷貝到src目錄下,並在classpath中導入Ice.jar。 
5) 、建立三個測試JAVA文件,Server.java、PrinterI.java及Client.java: 
PrinterI.java是對服務端實現骨架類_PrinterDisp的實現,返回時將PrinterI.java對象返回給客戶端,這里實現的功能是直接輸出傳入的String參數: 



    public class PrinterI extends Demo._PrinterDisp {  
        public void printString(String s, Ice.Current current) {  
            System.out.println(s);  
        }  
    }  

  Server.java是服務端服務代理,用於接收客戶端的請求操作: 



    public class Server {  
        public static void main(String[] args) {  
            int status = 0;  
            Ice.Communicator ic = null;  
            try {  
                //初使化連接,args可以傳一些初使化參數,如連接超時時間,初使化客戶連接池的數量等  
                ic = Ice.Util.initialize(args);  
                //創建名為SimplePrinterAdapter的適配器,並要求適配器使用缺省的協議(TCP/IP偵聽端口為10000的請求)  
                Ice.ObjectAdapter adapter = ic.createObjectAdapterWithEndpoints("SimplePrinterAdapter", "default -p 10000");  
                //實例化一個PrinterI對象,為Printer接口創建一個服務對象  
                Ice.Object object = new PrinterI();  
                //將服務單元增加到適配器中,並給服務對象指定名稱為SimplePrinter,該名稱用於唯一確定一個服務單元  
                adapter.add(object, Ice.Util.stringToIdentity("SimplePrinter"));  
                //激活適配器,這樣做的好處是可以等到所有資源就位后再觸發  
                adapter.activate();  
                //讓服務在退出之前,一直持續對請求的監聽  
                ic.waitForShutdown();  
            } catch (Ice.LocalException e) {  
                e.printStackTrace();  
                status = 1;  
            } catch (Exception e) {  
                System.err.println(e.getMessage());  
                status = 1;  
            }  
            if (ic != null) {  
                // Clean up  
                //  
                try {  
                    ic.destroy();  
                } catch (Exception e) {  
                    System.err.println(e.getMessage());  
                    status = 1;  
                }  
            }  
            System.exit(status);  
        }  
    }  

Client.java是客戶端代碼,用於向服務端發起請求,並操作返回的代理對象: 

    public class Client {  
        public static void main(String[] args) {  
            int status = 0;  
            Ice.Communicator ic = null;  
            try {  
                //初使化  
                ic = Ice.Util.initialize(args);  
                //傳入遠程服務單元的名稱、網絡協議、IP及端口,獲取Printer的遠程代理,這里使用的stringToProxy方式  
                Ice.ObjectPrx base = ic.stringToProxy("SimplePrinter:default -p 10000");  
                //通過checkedCast向下轉換,獲取Printer接口的遠程,並同時檢測根據傳入的名稱獲取的服務單元是否Printer的代理接口,如果不是則返回null對象  
                Demo.PrinterPrx printer = Demo.PrinterPrxHelper.checkedCast(base);  
                if (printer == null) throw new Error("Invalid proxy");  
                //把Hello World傳給服務端,讓服務端打印出來,因為這個方法最終會在服務端上執行  
                printer.printString("Hello World!");  
            } catch (Ice.LocalException e) {  
                e.printStackTrace();  
                status = 1;  
            } catch (Exception e) {  
                System.err.println(e.getMessage());  
                status = 1;  
            }  
            if (ic != null) {  
                // Clean up  
                //  
                try {  
                    ic.destroy();  
                } catch (Exception e) {  
                    System.err.println(e.getMessage());  
                    status = 1;  
                }  
            }  
            System.exit(status);  
        }  
    }  

6)、運行客戶端和服務端 
運行服務端:java Server 
運行客戶端:java Client 
看看效果吧。 

7、ICE的性能和效率 
ICE的性能是比較好的,因為他本身的傳輸機制都是基於二進制,網上有人曾經做過性能測試,評價比較好,我本人還沒有做性能測試,目前的判斷只是基於網絡數據,請先看下面的文章: 
高性能計算-ICE 性能測試 
ICE與CORBA比較的優勢 
8、ICE的優點 
支持同步和異步的消息傳遞; 
支持多個接口; 
機器無關性,客戶及服務器與底層的機器架構屏蔽開來。對於應用代碼而言,像字節序和填充這樣的問題都隱藏了起來; 
語言無關性,客戶和服務器可以分別部署,所用語言也可以不同; 
實現無關性,客戶不知道服務器是怎樣實現其對象的。這意味着,在客戶部署之后,服務器的實現可以改變; 
操作系統無關性,Ice API 完全是可移植的,所以同樣的源碼能夠在 Windows和 UNIX 
上編譯和運行; 
線程支持,Ice run time 完全是線程化的,其 API 是線程安全的,作為應用開發者,(除了在訪問共享數據時進行同步)無需為開發線程化的高性能客戶和服務器付出額外努力。 
傳輸機制無關性,Ice 目前采用了TCP/IP 和 UDP作為傳輸協議。客戶和服務器代碼都不需要了解底層的傳輸機制; 
位置和服務器透明性,Ice run time 會負責定位對象,並管理底層的傳輸機制,比如打開和關閉連接; 
安全性,通過 SSL強加密,可以使客戶和服務器完全安全地進行通信,這樣,應用可以使用不安全的網絡安全地進行通信,你可以使用 Glacier穿過防火牆,實現安全的請求轉發,並且完全支持回調; 
內建的持久機制,使用 Freeze,創建持久的對象實現變成了一件很容易的事情,Ice提供了對高性能數據庫 Berkeley DB[18] 的內建支持; 
開放源碼。 

后記 
這里只是簡單的對ICE進行介紹,還有很多東西沒有提到,如ICE的語法規則、ICE的版本控制(Facet)、持久化 (Feeze)、服務裝箱管理 (ICEBox)、文件分發(ICEPatch2)、發布/訂閱 服務(ICEStorm)、網絡拓撲負載解決方案--終極武器(ICEGrid)、提供使用安全傳輸入協議SSL的插件(IceSSL)、輕量級的ICE應用防火牆其解決方案(Galcier2),這些留待大家后面去學習了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM