1 本文介紹一個hello world輸出的例子。c++
ice應用的步驟以下:服務器
基本框架圖示:框架
本文代碼圖示:函數
須要注意的概念:spa
servant servant實際上是服務端實質的動做代碼.一個servant 提供一個或多個Ice 對象的實質內容。實際上,servant 就是服務器開發者編寫的類的實例,代理
對象適配器 是對象(或者說是servant)的代理。(1)包含端點地址和對象。適配器和端點地址綁定,對象是註冊到對象適配器中的。(2) 只有間接代理時候,客戶端纔用到適配器server
服務端就是 創建適配器,把對象(servant)註冊進適配器的過程對象
客戶端就是 鏈接適配器,得到對象(servant) 的過程繼承
2 咱們須要3個程序.接口
2.1 編寫 Slice 定義 編寫任何 Ice 應用的第一步都是要編寫一個 Slice 定義,其中含有應用所用的各個接口。
module demo
{
interface Printer { void printString(string s); }
}; 咱們把這段文本保存在叫做 Printer.ice 的文件中。 咱們的 Slice 定義含有一個接口,叫做 Printer。目前,咱們的接口很是簡單,只提供了一個操做,叫做 printString。 printString 操做接受一個 串做爲它惟一的輸入參數;這個串的文本將會出如今 (可能在遠地的)打印機上。
要建立咱們的 C++ 應用,第一步是要編譯咱們的 Slice 定義,生成 C++ 代理和骨架。在 UNIX 上,你能夠這樣編譯定義: $ slice2cpp Printer.ice slice2cpp 編譯器根據這個定義生成兩個 C++ 源文件:Printer.h 和Printer.cpp。 • Printer.h Printer.h 頭文件含有與咱們的 Printer 接口的 Slice 定義相對應的C++ 類型定義。在客戶和服務器源碼中必須包括這個頭文件。 • Printer.cpp Printer.cpp 文件含有咱們的 Printer 接口的源碼。所生成的源碼同時爲客戶和服務器提供針對特定類型的運行時支持。例如,它包含了 在客戶端整編參數數據 (傳給 printString 操做的串)的代碼,以及在服務器端解編數據的代碼。咱們必須編譯 Printer.cpp 文件,並把它連接進客戶和服務器。
2 編寫和編譯服務器
總結服務端代碼流程:
創建適配器,創建servant。適配器和servant綁定。激活ice通訊器
服務器的源碼很少,下面給出了其完整代碼:
#include <Ice/Ice.h> #include <Printer.h> using namespace std;
using namespace Demo; class PrinterI : public Printer { public: virtual void printString(const string & s, const Ice::Current &); };//繼承自slice提供了接口 void PrinterI::printString(const string & s, const Ice::Current &) { cout << s << endl; } int main(int argc, char* argv[]) { int status = 0; Ice::CommunicatorPtr ic; try { ic = Ice::initialize(argc, argv);//通訊器初始化,獲得運行時支持 Ice::ObjectAdapterPtr adapter= ic->createObjectAdapterWithEndpoints( "SimplePrinterAdapter", "default -p 10000");//通訊器建立對象適配器,適配器接受客戶請求,並把請求發送給服務器。括號中是適配器名字和監聽地址-----適配器綁定端點地址 Ice::ObjectPtr object = new PrinterI;//建立一個servant,其實就是服務器對象的實質處理函數 adapter->add(object,ic->stringToIdentity("SimplePrinter"));適配器與servant綁定。括號內是servant和servant名字 或者說 把服務端對象註冊進適配器中 adapter->activate();適配器激活 ic->waitForShutdown();//通訊器等待關閉 } catch (const Ice::Exception & e) { cerr << e << endl; status = 1; } catch (const char * msg) { cerr << msg << endl; status = 1; } if (ic) ic->destroy(); return status; } $ g++ -I. -I$ICE_HOME/include -c Printer.cpp Server.cpp c++ -o server Printer.o Server.o \ -L$ICE_HOME/lib -lIce -lIceUtil
3 客戶端程序
總結客戶端代碼流程:
使用servant名稱和適配器地址創建代理,代理轉換爲繼承類的servant
#include <Ice/Ice.h> #include <Printer.h> using namespace std;
using namespace Demo; int main(int argc, char * argv[]) { int status = 0;
Ice::CommunicatorPtr ic; try { ic = Ice::initialize(argc, argv); //初始化通訊器 Ice::ObjectPrx base = ic->stringToProxy("SimplePrinter:default -p 10000");//得到服務器對象的代理。括號內是對象和端點地址,即在某個端點地址上的某個對象 PrinterPrx printer = PrinterPrx::checkedCast(base);//解釋以下 if (!printer) throw "Invalid proxy"; printer->printString("Hello World!");//直接調用服務端函數 } catch (const Ice::Exception & ex) { cerr << ex << endl; status = 1; } catch (const char * msg) { cerr << msg << endl; status = 1; } if (ic) ic->destroy(); return status; }
stringToProxy 返回的代理的類型是 Ice::ObjectPrx,這種類型位於接口和類的繼承樹的根部。但要實際與咱們的打印機交談,咱們需 要的是 Printer 接口、而不是 Object 接口的代理。爲此,咱們須要調用 PrinterPrx::checkedCast 進行向下轉換。這個方法會發送一 條消息給服務器,實際詢問 「這是 Printer 接口的代理嗎?」若是是,這個調用就會返回 Printer 的一個代理;若是代理表明的是其餘類型的 接口,這個調用就會返回一個空代理。
客戶的編譯和連接看起來與服務器很像: $ c++ -I. -I$ICE_HOME/include -c Printer.cpp Client.cpp $ c++ -o client Printer.o Client.o -L$ICE_HOME/lib -lIce -lIceUtil
4 運行客戶和服務器 要運行客戶和服務器,咱們首先要在一個單獨的窗口中啓動服務器: $ ./server 咱們在這時不會看到任何東西,由於服務器會簡單地等待客戶與它連 接。咱們在另一個窗口中運行客戶: $ ./client $ 客戶會運行並退出,不產生任何輸出;但在服務器窗口中,咱們會看到 打印機產生的 "Hello World!"。要終止服務器,咱們目前的作法是在命 令行上中斷它 (咱們將在 10.3.1 節看到更乾淨的服務器終止方式)