`

ICE之Application 和 slice到C++映射

阅读更多

ICE是ZeroC公司开发的一款高效的开源中间件平台,全称是Internet Communications Engine。

它的主要设计目标是:
1 提供适用于异种环境的面向对象中间件平台。
2 提供一组完整的特性,支持广泛的领域中的实际的分布式应用的开发。
3避免不必要的复杂性,使平台更易于学习和使用。
4 提供一种在网络带宽、内存使用和 CPU 开销方面都很高效的实现。
5提供一种具有内建安全性的实现,使它适用于不安全的公共网络。

ICE支持多种编程语言:C++、Java、C#、VB、Python、Ruby,也就是说使用ICE时我们可以让这些语言无缝沟通,不过由于ICE是用C++编写的,不管用什么语言,你都需要先用C++编译出一个ICE才行(或者下载已编译的版本)。

本篇文章以C++语言作为演示语言,其它语言除语法不同外,使用方法非常类似。

配置ICE开发环境

首先,从http://www.zeroc.com/download.html 下载ICE,目前最新版本是Ice-3.3.1。下载页面里除了ICE的源码之外,也提供了VC或C++Builder的已编译安装包以及各Linux版本的RPM下载。

如果下载的是源码版本,编译方法是(以VC2005 Express为例):

1. ICE需要一些第三方库,在编译ICE之前要先编译第三方库,清单如下(它们也能在ICE官网上下载):

Berkeley DB  expat  OpenSSL  bzip2  mcpp

2. 编译完上面这些库以后,把它们放到同一个目录中,然后设置环境变量THIRDPARTY_HOME:

set THIRDPARTY_HOME = d:\ice3party

3. 打开$ICE/cpp/Make.rules.mak,找到CPP_COMPILER变量,改成CPP_COMPILER = VC80_EXPRESS
    这个依据你的编译器决定,可以是VC60, VC80, VC80_EXPRESS, VC90, VC90_EXPRESS, BCC2007, BCC2009

4. 如果想让编译的库能脱离VC运行时库,打开$ICE/cpp/Make.rules.msvc,把CPPFLAGS    = $(CPPFLAGS) -MD改成CPPFLAGS    = $(CPPFLAGS) -MT。

5. 在命令行下进入$ICE/cpp目录,输入nmake -f Makefile.mak开始编译。默认是编译成Debug模式的DLL库。如果想编译成静态库,可以设置变量STATICLIBS=yes;想编译成Release模式,设置OPTIMIZE=yes。如

nmake -f Makefile.mak STATICLIBS=yes OPTIMIZE=yes

如果按上面方法设置,应该不会有问题。

6. 最最后,把bin目录加入path变量,以便让系统能找到ICE的dll文件(其实主要是三个dll文件,ice33.dll、iceutil33.dll和bzip2.dll)

以后编译ICE的程序时,把上面编译好或直接下载的已编译版本的ice.lib和iceutil.lib(或Debug版本的iced.lib和iceutild.lib)链接入项目即可。

 

 

ICE的HelloWorld

跨语言的分布式系统首先要定义一个与编程语言无关的接口描述语法,用于分布于各处的服务器与客户端之间对话。比如DCOM和CORBA使用IDL语法,SOAP使用WSDL语法,当然还有时下流行的JSON。

ICE使用的是称为Slice(Specificatoin Language for Ice)的语法,Slice语法和C++(或Java,C#)比较相近,只要会C++(或Java,C#)很容易就能写Slice定义了

下面是一个简单的接口的Slice定义:

  1. module Demo {
  2.     interface Printer {
  3.         void printString(string s);
  4.     };
  5. };

它定义一个Printer接口(interface),这个接口只有一个printString方法,输入参数是一个字符串(string)。最后,这个接口位于Demo模块(module)之下。

把它保存为Printer.ice后接着我们使用slice2cpp程序依据这个Slice定义生成C++使用的头文件和对应的代理代码:

slice2cpp Printer.ice

如果没提示错误,就会生成Printer.h和Printer.cpp,把这两个文件加入到服务器端项目和客户端项目后就可以互相对话了。

下表是Slice与C++的映射关系

Slice C++
#include #include
#ifndef #ifndef
#define #define
#endif #endif
module namespace
bool bool
byte Ice::Byte
short Ice::Short
int Ice::Int
long Ice::Long
float Ice::Float
double Ice::Double
string Ice::string
enum enum(不支持指定数字)
struct struct
class class(所有方法都是纯虚函数)
interface struct(所有方法都是纯虚函数,没有成员变量)
sequence<T> std::vector<T>
dictionary<Key,Value> std::map<Key,Value>
exception Err class Err:public Ice:UserException
nonmutating方法限定符 const方法
idempotent方法限定符 -
out 参数限定符 引用类型
* 对应类型的代理类

参考这个表,可以知道上面的Slice定义对应的C++映射如下:

  1. namespace Demo {
  2.     struct Printer {
  3.         virtual void printString(string s) = 0;
  4.     };
  5. };

严格地说,C++中对应的Printer类还继承自IceProxy::Ice::Object,目前我们可以不理这个问题

我们只要在服务器端实现这个printString方法,就可以在客户端简单地调用它了。

编写服务器端代码:

  1. 新建一个控制台项目
  2. 将$ICE\include添加到头文件目录列表中
  3. 将$ICE\lib\ice.lib和iceutil.lib(对应的Debug版本是iced.lib和iceutild.lib)链接入项目
  4. 把生成Printer.cpp加入项目
  1. #include <ice/ice.h>
  2. #include "printer.h"  //slice2cpp生成的文件
  3. using namespace std;
  4. using namespace Demo;
  5. //实现printString方法
  6. struct PrinterImp : Printer{
  7.     virtual void printString(const ::std::string& s,
  8.         const ::Ice::Current& = ::Ice::Current())
  9.     {
  10.         cout << s << endl;  
  11.     }
  12. };
  13. int main(int argc, char* argv[])
  14. {
  15.     Ice::CommunicatorPtr ic;
  16.     try{
  17.         // 初始化Ice运行库
  18.         ic = Ice::initialize(argc, argv);
  19.         // 建立ObjectAdapter,命名为SimplePrinterAdapter
  20.         // 使用默认协议(一般是tcp)并在10000端口监听。
  21.         Ice::ObjectAdapterPtr adapter
  22.             = ic->createObjectAdapterWithEndpoints(
  23.                 "SimplePrinterAdapter""default -p 10000");
  24.         // 把我们实现的Printer加入ObjectAdapter,并命名为SimplePrinter
  25.         Ice::ObjectPtr object = new PrinterImp;
  26.         adapter->add(object, ic->stringToIdentity("SimplePrinter"));
  27.         adapter->activate();
  28.         // 等待直到Communicator关闭
  29.         ic->waitForShutdown();
  30.     }
  31.     catch(const Ice::Exception &e){
  32.         cerr << e << endl;
  33.     }
  34.     catch(const char* msg){
  35.         cerr << msg << endl;
  36.     }
  37.     // 回收Ice运行库所用的资源
  38.     if(ic) ic->destroy();
  39.   
  40.     return 0;
  41. }

客户端代码:

  1. #include <ice/ice.h>
  2. #include <printer.h>
  3. using namespace std;
  4. using namespace Demo;
  5. int main(int argc, char* argv[])
  6. {
  7.     Ice::CommunicatorPtr ic;
  8.     try{
  9.         // 初始化Ice运行库
  10.         ic = Ice::initialize(argc, argv);
  11.         // 在10000端口取得SimplePrinter代理对象
  12.         Ice::ObjectPrx base = ic->stringToProxy("SimplePrinter:default -p 10000");
  13.         // 把对象转换成Printer代理
  14.         PrinterPrx printer =  PrinterPrx::checkedCast(base);
  15.         if(!printer) throw "Invalid Proxy!";
  16.         // 能过这个代码调用printString方法
  17.         printer->printString("Hello World!");
  18.     }
  19.     catch(const Ice::Exception &e){
  20.         cerr << e << endl;
  21.     }
  22.     catch(const char* msg){
  23.         cerr << msg << endl;
  24.     }
  25.     // 回收Ice运行库所用的资源
  26.     if(ic) ic->destroy();
  27.   
  28.     return 0;
  29. }

编译服务器端和客户端,然后启动一个服务器端,每次调用客户端后服务器端会显示一行Hello world!

你也可以把服务器端放到别的电脑上,客户端代码改成:Ice::ObjectPrx base = ic->stringToProxy("SimplePrinter:default -h 服务端IP -p 10000");即可实现远程调用。

看上去我们写一个Helloworld的程序要弄这么一大堆的东西,不过实际上只要我们修改Slice定义,我们就可实现更强大的功能,而代码并不需要多大变化。

 

使用Ice::Application简化代码的编写

对比上例中的服务端和客户端代码,可以发现占很大比例的代码都是初始化、异常捕捉、回收资源这样的“样板”代码。ICE针对这些“样板”代码提供了Ice::Application类来封装它们(而且它做得更多),通过它我们就可以简化上例中了代码了。

Ice::Application中有一个纯虚函数

virtual int run(int, char*[]) = 0;


我们只要实现这个run方法,其它的一切都由Application完成:

服务器端:

  1. #include <ice/ice.h>
  2. #include "printer.h"
  3. using namespace std;
  4. using namespace Demo;
  5. struct PrinterImp : Printer{
  6.     virtual void printString(const ::std::string& s, const ::Ice::Current& = ::Ice::Current())
  7.     {
  8.         cout << s << endl;  
  9.     }
  10. };
  11. class MyApp : public Ice::Application{
  12. public:
  13.     virtual int run(intchar*[]){
  14.         Ice::CommunicatorPtr& ic = communicator();
  15.         Ice::ObjectAdapterPtr adapter
  16.             = ic->createObjectAdapterWithEndpoints(
  17.                 "SimplePrinterAdapter""default -p 10000");
  18.         Ice::ObjectPtr object = new PrinterImp;
  19.         adapter->add(object, ic->stringToIdentity("SimplePrinter"));
  20.         adapter->activate();
  21.         ic->waitForShutdown();
  22.         return 0;
  23.     }
  24. };
  25. int main(int argc, char* argv[])
  26. {
  27.     MyApp app;
  28.     return app.main(argc, argv);
  29. }

原来的版本我们的退出方法只能使用很野蛮的强行退出,现在,服务端可以检测到Ctrl+C这样的退出信号了。

客户端:

  1. #include <ice/ice.h>
  2. #include <printer.h>
  3. using namespace std;
  4. using namespace Demo;
  5. class MyApp: public Ice::Application{
  6. public:
  7.     virtual int run(intchar*[])
  8.     {
  9.         Ice::CommunicatorPtr ic = communicator();
  10.         Ice::ObjectPrx base = ic->stringToProxy("SimplePrinter:default -p 10000");
  11.         PrinterPrx printer =  PrinterPrx::checkedCast(base);
  12.         if(!printer) throw "Invalid Proxy!";
  13.         printer->printString("Hello World!");
  14.     }
  15. };
  16. int main(int argc, char* argv[])
  17. {
  18.     MyApp app;
  19.     return app.main(argc,argv);
  20. }
分享到:
评论

相关推荐

    zeroc ice教程 ice环境配置 Ice中文教程 C++ ICE java ICE ICE入门 ice基础教程 ice开发文档

    从编程语言映射的角度看,文档深入讲解了Slice到C++和Java的映射机制。在C++映射章节中,文档涵盖了标识符映射、模块映射、简单内建类型映射、用户定义类型映射、接口映射、操作映射以及异常处理等。这些内容对开发...

    ICE框架 C++示例程序

    4. **自动类型映射**:ICE支持基本数据类型和自定义类型的自动序列化和反序列化,简化了数据交换的过程。 5. **透明的负载均衡和故障恢复**:ICE内置了负载均衡和故障恢复机制,可以动态调整服务实例,确保系统的高...

    Zeroc ICE中间件slice2java的ant脚本(v1u0_0)

    `slice2java`是ICE提供的一个工具,它可以将`slice`文件转换为Java语言的接口和数据类型实现。 在这个名为"Zeroc ICE中间件slice2java的ant脚本(v1u0_0)"的资源中,包含了一个Ant构建脚本`slice2java.xml`。Ant是...

    Ice-3.4.0中文开发手册1

    在Slice语言章节之后,手册详细阐述了Slice到C++和Java的映射,这有助于开发者理解如何将Slice定义转换为实际的代码。对于C++,讲解了标识符、模块、类型、常量、异常、接口和操作的映射规则,以及异常处理和类的...

    Zeroc ICE中间件slice2java的ant脚本

    Ice支持多种编程语言,包括Java,C++,Python等,使得应用程序能够轻松地进行网络通信和数据交换。在分布式系统中,中间件起到桥梁的作用,简化了不同组件之间的通信。 “slice2java”是Ice工具集的一部分,用于将 ...

    Ice-1.3.0-中文文档.pdf

    - 书籍讨论了如何将Slice定义映射到C++和Java客户端代码。 - 涉及了标识符映射、模块映射、类型映射以及如何处理异常等。 - 提供了slice2cpp和slice2java命令行选项的说明。 8. 具体应用示例: - 书中通过实现一...

    ICE中间件教程

    - **1.3.2 Slice映射机制**:定义了如何将Slice中的定义映射到具体的编程语言中,如C++或Java。 **1.4 Ice协议** - **1.4.1 Ice协议的组成**:包括消息格式、序列化规则等,确保客户端和服务器之间的通信能够高效...

    ice分布式程序设计中文版

    书籍涵盖了ICE的核心概念、Slice语言的使用、以及如何将Slice定义转换为C++和Java代码。 书中第一部分着重于ICE的综述,包括ICE的基本架构、服务以及它与传统分布式对象计算模型CORBA的对比。作者提供了编写Hello...

    ICE分布式程序设计(中文版).pdf 本人亲测 内部资料

    - **Slice 到 C++ 和 Java 的映射**:ICE 提供了从 Slice 语言到具体编程语言(如 C++ 和 Java)的转换工具,帮助开发者更容易地进行分布式系统的开发工作。 - **C++ 映射**:书中详细介绍了 Slice 语言中的概念...

    ICE中文编程指南

    #### 五、客户端的Slice到语言映射 - **C++映射**: - Slice定义被转换成C++代码,包括头文件和实现文件。 - 映射规则包括标识符、类型、异常等方面的转换。 - **Java映射**: - Slice定义同样被转换成Java代码...

    ICE分布式程序设计中文版

    第 6 章 客户端的 Slice-to-C++ 映射 143 6.1 本章综 143 6.2 引言 143 6.3 标识符的映射 144 6.4 模块的映射 144 6.5 Ice 名字空间 145 6.6 简单内建类型的映射 146 6.7 用户定义类型的映射 146 6.8 常量的映射 150...

    ice分布式应用开发

    - **Ice**支持将Slice定义转换为C++或Java代码,从而简化了客户端和服务端的开发过程。映射规则主要包括: - 类型映射:将Slice中的类型映射为相应的C++或Java类型。 - 接口映射:将Slice接口映射为C++类或Java...

    zeroc ICE 教程

    第6章和第8章分别详细介绍了客户端的Slice-to-C++映射和Slice-to-Java映射。这些章节讨论了从Slice到不同编程语言的映射规则,包括标识符的映射、模块的映射、用户定义类型的映射、异常的映射等。这些内容是让ICE...

    ice中间件平台_中文教程

    _slice-to-C++和Slice-to-Java映射_ 这两个章节着重讨论了如何将Slice语言定义转换成C++和Java代码,以便开发者可以利用各自熟悉的编程语言进行开发。 - 开发C++文件系统客户端:文档提到了如何使用C++语言开发...

Global site tag (gtag.js) - Google Analytics