1、ICE是什么?
网络通信引擎ICE(Internet Communications Engine)是Zero C公司的分布式系统开发专家实现的一种新的高性能的面向对象中间件平台。从根本上说, ICE 为构建面向对象的客户-服务器应用提供了工具、 API( Application Program Interface)和库支持。 基于ICE可以实现电信级的解决方案。
2、为什么会有ICE?
ICE是分布式应用的一种比较好的解决方案,虽然现在也有一些比较流行的分布式应用解决方案,如微软的.NET(以及原来的DCOM)、CORBA及WEB SERVICE等,但是这些面向对象的中间件都存在一些不足:
.NET是微软产品,只面向WINDOWS系统,而实际的情况是在当前的网络环境下,不同的计算机会运行不同的系统,如LINUX上面就不可能使用.NET;
CORBA虽然在统一标准方面做了很多的工作,但是不同的供应商实现之间还是缺乏互操作性,并且目前还没有一家供应商可以针对所有的异种环境提供所有的实现支持,且CORBA的实现比较复杂,学习及实施的成本都会比较高;
WEB SERVICE最要命的缺点就是他的性能问题,对于要求比较高的行业是很少会考虑WEB SERVICE的。
ICE的产生就是源于.NET、CORBA及WEB SERVICE这些中间件的不足,它可以支持不同的系统,如WINDOWS、LINUX等,也可以支持在多种开发语言上使用,如C++、C、JAVA、RUBY、PYTHON、VB等,服务端可以是上面提到的任何一种语言实现的,客户端也可以根据自己的实际情况选择不同的语言实现,如服务端采用C语言实现,而客户端采用JAVA语言实现,底层的通讯逻辑通过ICE的封装实现,我们只需要关注业务逻辑。
3、ICE是如何工作的?
Ice 是一种面向对象的中间件平台,这意味着 Ice为构建面向对象的客户-服务器应用提供了工具、API 和库支持。要与Ice持有的对象进行通信,客户端必须持有这个对象的代理(与CORBA的引用是相同的意思),这里的代理指的是这个对象的实例,ICE在运行时会定位到这个对象,然后寻找或激活它,再把In参数传给远程对象,再通过Out参数获取返回结果。
这里提到的代理又分为直接代理和间接代理,直接代理其内部保存有某个对象的标识,以及它的服务器的运行地址;间接代理指的是其内部保存有某个对象的标识,以及对象适配器名(object adapter name),间接代理没有包含寻址信息,为了正确地定位服务器,客户端在运行时会使用代理内部的对象适配器名,将其传给某个定位器服务,比如IcePack服务,然后,定位器会把适配器名当作关键字,在含有服务器地址的表中进行查找,把当前的服务器地址返回给客户,客户端 run time现在知道了怎样联系服务器,就会像平常一样分派 (dispatch)客户请求。
ICE可以保证在任何的网络环境或者操作系统下,成功的调用只有一次,它在运行时会尽力的定位到远程服务器,在连接失败的情况下会做尝试性重复性连接,确实连不上的情况会给用户以提示。
客户端在调用服务端的方法时,可以采取同步或异步的方式实现,同步调用就相当于调用自己本地的方法一样,其它行为会被阻塞;异步调用是非常有用的调用方式,如服务端需要准备的数据来自于其它异步接口,这个时候客户端就不需要等待,待服务端数据准备充份后,以消息的方式通知客户端,服务端就可以去干其它的事情了,而客户端也可以到服务端获取数据了。
4、ICE调用模式
ICE采用的网络协议有TCP、UDP以及SSL三 种,不同于WebService,ICE在调用模式上有好几种选择方案,并且每种方案正对不同的网络协议的特性做了相应的选择。
Oneway(单向调用):客户端只需将调用注册到本地传输缓冲区(Local Transport Buffers)后就立即返回,不会等待调用结果的返回,不对调用结果负责。
Twoway(双向调用):最通用的模式,同步方法调用模式,只能用TCP或SSL协议。
Datagram(数据报):类似于Oneway调用,不同的是 Datagram调用只能采用UDP协议而且只能调用无返回值和无输出参数的方法。
BatchOneway(批量单向调用):先将调用存 在调用缓冲区里面,到达一定限额后自动批量发送所有请求(也可手动刷除缓冲区)。
BatchDatagram(批量数据报):与上类似。
不同的调用模式其实对应着不动的业务,对于大部分的有返回值的或需要实时响应的方法,我们可能都采用Twoway方式调用,对于一些无需返回值或 者不依赖返回值的业务,我们可以用Oneway或者BatchOneway方式,例如消息通知;剩下的Datagram和BatchDatagram方式 一般用在无返回值且不做可靠性检查的业务上,例如日志。
5、客户端与服务端的结构
这个图示显示了使用ICE做为中间件平台,客户端及服务端的应用都是由应用代码及ICE的库代码混合组成的。
客户应用及服务器应用分别对应用的是客户端与服务端。
代理是根据SLICE定义的ice文件实现,它提供了一个向下调用的接口,提供了数据的序列化与反序化。
ICE的核心部份,提供了客户端与服务端的网络连接等核心通信功能,以及其它的网络通信功能的实现及可能的问题的处理,让我们在编写应用代码的时候不必要去关注这一块,而专注于应用功能的实现。
6.安装ICE客户端
6.1首先下载客户端
http://www.zeroc.com/download.html 根据操作系统和需要选择
6.2 安装完成之后配置环境变量
然后在dos模式下运行 icegridnode --version
返回对应版本号就为成功
6.3 准备一个对应的ice文件
内容如下:
module demo { interface MyIce { string queryMyIce(string request); } }
目录结构如下:
然后在MyIce.ice所在目录 运行命令:slice2java MyIce.ice
自动创建对应java文件
在项目工程中加入pom信息:
<dependency> <groupId>com.zeroc</groupId> <artifactId>ice</artifactId> <version>3.7.1</version> </dependency> <dependency> <groupId>com.zeroc</groupId> <artifactId>icebox</artifactId> <version>3.7.1</version> </dependency>
实现MyIce.java的接口
package com.wz; import com.zeroc.Ice.Current; public class MyIceImpl implements MyIce{ @Override public String queryMyIce(String request, Current current) { System.out.println("接收到消息:" + request); return "处理对应数据并返回"; } }
改实现类是服务端在收到对应数据并返回处理结果的具体实现。
创建服务端:
package com.wz.service.webServiceServer; import com.wz.MyIceImpl; import com.zeroc.Ice.Communicator; import com.zeroc.Ice.ObjectAdapter; import com.zeroc.Ice.Util; public class Server { public static void main(String[] args) { int state = 0; Communicator communicator = null; try { // 初始化ICE通信器communicator,可以使用args传入ice初始化的参数,如:超时时间、线程池的大小等 communicator = Util.initialize(args); // 撞见一个名为queryEmployeeAdapter的适配器 并且默认使用tcp协议 部署在10.0.0.1机器上 服务开启10006监听端口 ObjectAdapter adapter = communicator.createObjectAdapterWithEndpoints("queryServer", "default -h 127.0.0.1 -p 10086"); // 创建服务端代码实现实现类 com.zeroc.Ice.Object object = new MyIceImpl(); // 将服务端实现类与ice对象标识符简历映射关系,并添加到ice对象适配器中 adapter.add(object, Util.stringToIdentity("QUER_Order")); // 激活对象适配器 adapter.activate(); System.out.println("服务端已经激活"); // 服务在退出之前一直保持监听状态 communicator.waitForShutdown(); } catch (Exception e) { state = 1; System.out.println(e); e.printStackTrace(); } finally { if (communicator != null) { communicator.destroy(); } } System.out.println("state:" + state); } }
创建客户端:
package com.wz.service.webServiceServer; import com.wz.MyIcePrx; import com.zeroc.Ice.Communicator; import com.zeroc.Ice.ObjectPrx; import com.zeroc.Ice.Util; public class Client { public static void main(String[] args) throws Exception{ Communicator communicator = null; try { // 初始化ice通信器 设置超时时间 communicator = Util.initialize(); // 传入远程服务单元的ice对象标识符 ObjectPrx objectPrx = communicator.stringToProxy("QUER_Order:default -h 127.0.0.1 -p 10086"); // 检验是否连接上 MyIcePrx myIcePrx = MyIcePrx.checkedCast(objectPrx); if(myIcePrx==null){ System.err.println("未连接上"); throw new Exception("没有链接成功"); } String response = myIcePrx.queryMyIce("测试通信"); System.out.println("服务返回数据:"+response); } catch (Exception e) { e.printStackTrace(); } } }
分别启动服务端和客户端
完成简单通信。
7、ICE的性能和效率
ICE的性能是比较好的,因为他本身的传输机制都是基于二进制,网上有人曾经做过性能测试,评价比较好,我本人还没有做性能测试,目前的判断只是基于网络数据,请先看下面的文章:
高性能计算-ICE 性能测试
ICE与CORBA比较的优势
8、ICE的优点
支持同步和异步的消息传递;
支持多个接口;
机器无关性,客户及服务器与底层的机器架构屏蔽开来。对于应用代码而言,像字节序和填充这样的问题都隐藏了起来;
语言无关性,客户和服务器可以分别部署,所用语言也可以不同;
实现无关性,客户不知道服务器是怎样实现其对象的。这意味着,在客户部署之后,服务器的实现可以改变;
操作系统无关性,Ice API 完全是可移植的,所以同样的源码能够在 Windows和 UNIX
上编译和运行;
线程支持,Ice run time 完全是线程化的,其 API 是线程安全的,作为应用开发者,(除了在访问共享数据时进行同步)无需为开发线程化的高性能客户和服务器付出额外努力。
传输机制无关性,Ice 目前采用了TCP/IP 和 UDP作为传输协议。客户和服务器代码都不需要了解底层的传输机制;
位置和服务器透明性,Ice run time 会负责定位对象,并管理底层的传输机制,比如打开和关闭连接;
安全性,通过 SSL强加密,可以使客户和服务器完全安全地进行通信,这样,应用可以使用不安全的网络安全地进行通信,你可以使用 Glacier穿过防火墙,实现安全的请求转发,并且完全支持回调;
内建的持久机制,使用 Freeze,创建持久的对象实现变成了一件很容易的事情,Ice提供了对高性能数据库 Berkeley DB[18] 的内建支持;
开放源码。
后记
这里只是简单的对ICE进行介绍,还有很多东西没有提到,如ICE的语法规则、ICE的版本控制(Facet)、持久化 (Feeze)、服务装箱管理 (ICEBox)、文件分发(ICEPatch2)、发布/订阅 服务(ICEStorm)、网络拓扑负载解决方案–终极武器(ICEGrid)、提供使用安全传输入协议SSL的插件(IceSSL)、轻量级的ICE应用防火墙其解决方案(Galcier2),这些留待大家后面去学习了。
参考原文:https://blog.csdn.net/fenglibing/article/details/6372444