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 节看到更干净的服务器终止方式)