`

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. }
分享到:
评论

相关推荐

    Ice 分布式程序设计

    第 6 章 客户端的 Slice-to-C++ 映射 第 7 章开发 C++ 文件系统客户 第 8 章 客户端的 Slice-to-Java 映射 第 9 章开发 Java 文件系统客户 第 10 章 服务器端的 Slice-to-C++ 映射 第 11 章开发 C++ 文件系统服务器 ...

    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...

    zeroc ice微服务架构用户手册

    * Slice 语言:Slice 语言是 Ice 的一种描述语言,用于定义接口、数据类型和异常处理机制。 Terminology 在 Ice 架构模型中,存在一些重要的术语: * Interface:接口是指在 Slice 语言中定义的接口,用于描述一...

    string和slice.go

    string和slice.go

    Distributed Programming with Ice

    application in C++, Java, C#, Visual Basic, and Python. • Part II, Slice, explains the Slice definition language. After reading this part, you will have detailed knowledge of how to specify ...

    ICE客户端与服务端通信Demo

    平台编译环境:VS2017 ICE版本:3.7.7 ICEbuilder:5.0.9 源码中有两套程序: Server:启动服务器,等待连接 。连接后可双方通信 Client:连接服务器,与服务器通讯。...Slice: 手写几个接口即可。

    ICE异步调用Demo源码

    ICE异步调用Demo(slice源码和C++源码) 服务器和客户端adm ami函数调用与异步分发 vs2008+ice3.4.1

    ZeroC Ice 3.7 手册

    Ice通过与编程语言无关的中立语言Slice(Specification Language fro Ice)来描述服务的接口,从而达到对象接口与其实现想分离的目的。 目前Ice平台支持客户端API的语言有C++、.NET、Java、Python、Object-C、...

    zeroc_ice-3.7.6 for python win_amd64

    Internet 通信引擎 (Ice) 为开发任务关键型网络应用程序提供了一个强大的、经过验证的平台。让 Ice 处理所有底层细节,例如网络连接、序列化和并发性,以便您可以专注于应用程序逻辑。...从 Slice 到 Python 的直观映射

    gulp-ice-builder:Gulp插件,可自动将Slice文件编译为JavaScript

    slice2js gulp-ice-builder调用slice2js编译器。 您可以使用以下命令安装最新的 : npm install slice2js --save-dev 用法 const iceBuilder = require ( 'gulp-ice-builder' ) ; gulp . task ( "slice2js" , ( ) ...

    利用ICE通信中间件构建分布式应用程序开发框架

    中间件技术是计算机硬件和操作系统之上支持应用软件开发和运行的系统软件。它能够使应用软件相对独立于计算机硬件和操作系统平台。中间件具有标准的程序接口和协议,可以实现不同硬件和操作系统平台上的数据共享和...

    Zeroc ICE中间件slice2java的ant脚本

    NULL 博文链接:https://zhaoningbo.iteye.com/blog/1071365

    slice2qt ice3.5.1 qt5.30版本

    qt使用ice时需要的代码转换工具。之前网上的版本最多支持到qt4.3,本版本支持qt5.3.0 ice3.5.1,应该是目前最新的版本。修改和增加的功能是手动修改的,并不一定适用所有项目,需要根据具体情况修改部分代码。

    Ice-3.7.1.rar

     Ice通过与编程语言无关的中立语言Slice(Specification Language fro Ice)来描述服务的接口,从而达到对象接口与其实现想分离的目的。  目前Ice平台支持客户端API的语言有C++、.NET、Java、Python、Object-C、...

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

    NULL 博文链接:https://zhaoningbo.iteye.com/blog/1135564

    eclipse Slice2Java

    eclipse Slice2Java 控件 jar ,eclipse Slice2Java 控件 jar

    Philips Slice Timing Options

    Philips 机器进行BOLD-fMRI扫描时的扫描顺序选择卡说明,建议扫描前阅读,使用适当的slice order,也有利于在以后进行数据处理时输入正确的slice order

    npm-slice2js:Slice到JavaScript编译器的Npm软件包

    slice2js 将Slice文件编译为JavaScript。 安装 npm install slice2js --save-dev... 将DIR添加到Slice文件的包含路径。 -E 在标准输出上打印预处理器输出。 --stdout 将生成的代码打印到stdout。 --output-dir DI

Global site tag (gtag.js) - Google Analytics