ICE第二篇--一个"hello world"的简单例子

1 本文介绍一个hello world输出的例子。

ice应用的步骤如下:

1. 编写 Slice 定义并编译它。

2. 编写服务器并编译它。

3. 编写客户并编译它。

基本框架图示:

ICE第二篇--一个"hello world"的简单例子

本文代码图示:

ICE第二篇--一个"hello world"的简单例子

需要注意的概念:

servant  
servant其实是服务端实质的动作代码.一个servant 提供一个或多个Ice 对象的实质内容。实际上,servant 就是服务器开发者编写的类的实例,

对象适配器      是对象(或者说是servant)的代理。(1)包含端点地址和对象。适配器和端点地址绑定,对象是注册到对象适配器中的。(2)   只有间接代理时候,客户端才用到适配器

服务端就是   建立适配器,把对象(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 节看到更干净的服务器终止方式)

本文主要内容来自《ice分布式设计》

上一篇:查看Eclipse版本号的方法及各个版本区别 Eclipse选择标准


下一篇:Android UI开发第三十一篇——Android的Holo Theme