网络通信引擎(Internet Communications Engine, Ice)是由ZeroC的分布式系统开发专家实现的一种高性能、面向对象的中间件平台。它号称标准统一,开源,跨平台,跨语言,分布式,安全,服务透明,负载均衡,面向对象,性能优越,防火墙穿透,通讯屏蔽。因此相比CORBA,DCOM,SOAP,J2EE等的中间件技术,自然是集众多优点于一身,而却没有他们的缺点。
Ice提供了完善的分布式系统解决方案,适合所有的异构网络环境:客户端和服务器端可以用不同的程序语言来实现,可以运行在不同的操作系统和不同的体系结构的机器上,使用不同的网络通信技术(TCP/UDP,SSL或通过插件功能扩展协议)。Ice也提供了客户端和服务器端的完全分离,客户端不需要知道服务器的实现过程和具体位置。Ice采用软总线的机制,使得在任何情况下、采用任何语言开发的软件只要符合接口规范的定义,均能集成到分布式环境中去。Ice面向对象,可以将所有应用看作是对象及相关操作的集合,构建在Ice之上的分布式系统的对象的获取只取决于网络的通畅性和获取服务对象特征的准确程度,而与对象的位置以及对象所处的设备环境无关。
1.2 ICE结构
Ice是一种面向对象的中间件平台,从根本上说,这意味着Ice为构建面向对象的客户/服务器模式的应用提供了工具、应用程序接口(API)和库支持。
1.2.1 客户端和服务器
客户端是主动的实体,向服务器端发出服务请求;服务器端是被动的实体,他们提供服务,响应客户端的请求。这两个角色并不是应用系统的组成部分的严格指称,而是表示在某个请求从发生到结束期间,应用系统某些部分所承担的角色。通常这样的角色界定是不固定的,甚至会经常性的发生反转行为。所以,许多客户/服务器常可以被准确的描述为对等系统(peer-to-peer),客户端和服务器角色只有在执行某个特定操作、在特定的时间能才有绝对意义。
1.2.2 Ice核心
Ice核心包含大量的链接库,是处于核心地位的对象总线,为客户端和服务器的远程通信提供支持。它主要关心的是网络通信、线程、字节序、其它一些网络细节及相关事务等,并将应用程序与这些底层事务隔离开。
Ice核心定义了异构环境下对象透明的发送请求和接收响应的基本机制,是建立对象之间客户端/服务器模型的核心组件。它使对象可以透明的向其它对象发出请求或者接收其它对象的响应,这些对象可以位于本地也可以位于远端机器。Ice核心截获客户端的请求调用,找到可以实现请求的服务器对象,并负责传送参数、调用相应的方法、返回结果等。客户端对象并不需要了解和服务器对象的通信、激活或存储服务期对象的机制,也不需要服务器对象位于何处、用何种语言实现、使用什么操作系统或其它不属于对象接口的系统部分。对于服务器对象,也是如此。
Ice核心提供一种客户段/服务器的松耦合通信方式,使得开发人员可以把更多的注意力放在应用逻辑的实现上。
1.2.4 对象适配器
对象适配器是专用于服务器端的Ice API的一部分:只有服务器才使用对象适配器。对象服务器有若干功能,如下所列:
1. 对象适配器把来自客户端的请求映射到服务器端特定对象的特定方法上。
2. 对象适配器会跟踪在内存中的伺服对象,记录其对象标识,从而实现适配请求的功能。
3. 对象适配器可以与一个或多个传输端点关联在一起。如果与某个适配器关联的传输端点不止一个,就可以通过多种传输机制到达在该适配器中的伺服对象。为了提供不同的服务质量和性能,一个适配器可以同时关联一个TCP/IP|端点和一个UDP端点。
4. 对象适配器负责创建传给客户端的Ice代理。对象适配器知道每个对象的类型、标识以及传输机制的详细信息。当服务器端应用程序要求创建代理时,对象适配器会在其中嵌入正确的信息。
1.2.5 Ice代理
代理代码是由用户定义的Slice文件经过编译后生成的。一个客户端要想与一个Ice对象建立联系,必须持有该Ice对象的代理。代理是存在于客户端地址空间的该Ice对象的代表。代理主要有两个功能:
1. 为客户提供了一个向下(down-call)调用的接口。如果客户端调用代理中的某个操作,就会有一个RPC消息被发送到服务器,从而调用目标对象上的某个对应的操作。以代理为中介,客户端发起的调用最终会调用到服务器目标对象上相应的操作。
2. 提供编码(marshaling)和解码(unmarshaling)。编码是将复杂的数据结构串行化,使其便于网络传输的过程。编码把数据转化为适合于传送的标准形式,这种形式不依赖于本地机器的字节序和填充规则。解码是编码的逆过程,将通过网络得到的串化数据重新构造成具有类型的结构化数据。解码之后得到的是与所使用的编程语言相适应的类型表示的数据。
1.2.6 Ice骨架(skeleton)
骨架代码也是由用户定义的Slice文件经过编译后生成的,其中的内容与Slice中定义的对象和数据的类型是对应的。骨架代码是客户端的代理代码在服务器端的等价物。它提供了向上调用(up-call)的接口,允许Ice把控制线程转交给服务器端的应用程序代码。骨架也负责编码和解码,所以服务器可以接收客户端发送的参数,并把返回值和异常传回客户。
1.4.1 Ice协议的组成
Ice提供了一个RPC(Remote Procedure Call)协议,该协议能够运行在各种流传输和数据报传输协议上。目前,该协议支持TCP、UDP和SSL作为底层的传输机制。使用SSL协议时,客户端和服务器端之间的所有通信都可以进行加密,以确保传输的安全性。Ice协议的引擎是可以扩展的,开发人员可以通过增加API插件来增加新的底层传输协议,而不用修改源代码,Ice的SSL传输就采用了这种插件结构。Ice协议定义由三个主要部分组成:
1. 数据编码规则:确定各种数据类型的串行化方式。
2. 协议状态机制:规定客户端和服务器如何交互不同类型的信息。
3. 版本控制:确定客户端和服务器怎样就特定的协议和编码版本达成一致。编码规则和状态机制使用各自独立的版本号,从而保证了良好的向后兼容性。
1.4.4 协议状态机制
Ice只有五种协议消息,相对于其它通信协议相当简单。他们分别是:
从客户端发到服务器的请求;
从客户端发到服务器的批请求;
从服务器端发到客户端的答复;
从服务器端发到客户端的验证连接信息;
双向发送的关闭连接消息;
在这些消息里,验证和关闭连接消息只用于面向连接的传输机制。
和数据编码一样,协议消息也没有对齐限制。除了验证和关闭连接消息。每个消息都由一个消息头和一个紧跟其后的消息体组成。
1.5.2 IceGrid
IceGrid是Ice定位服务器的一种实现,它从间接绑定的协议-地址对中将一个间接代理中的符号信息解析出来,IceGrid除了能够提供简单的服务对象定位功能,还提供了一些网格计算的特性。
客户端通过代理发起调用请求,代理分为直接代理和间接代理。直接代理中保存有服务器的地址的详细信息,使用该信息,直接代理可以直接连接到服务器。而间接代理中只包含对象适配器的信息,没有任何服务器端的地址信息。但是,间接代理是一种更为常见的代理方式,因为间接代理支持服务器的透明迁移,即使服务器地址改变,客户端所持有的已有代理也不会失效。如果使用的是直接代理,虽然不用为了定位服务器而进行额外的查找,但是如果服务器被转移到其他机器上,代理就不能继续工作了。可见定位服务器在分布式系统中是相当最重要的,可以大大提高系统的灵活性。
在IceGrid中维护了记录着对象适配器和服务器地址的对应关系映射表。通过检索这张表,客户端就能获取服务器端当前的地址信息,这个过程类似于通过DNS将网络域名映射成IP地址。通过这种间接代理和IceGrid相结合的方式,服务器的迁移将不会影响到客户端的正常工作。
IceGrid提供了对象查找的服务,客户端可用来获取他们感兴趣的对象代理。除此以外,还提供了服务器激活服务:当客户端发起请求时,服务器可能处于未运行状态,IceGrid会在第一个客户请求到达时,随需启动服务器。通过这个服务,开发人员可以轻松配置包含若干服务期的复杂应用。
1.6 Ice架构的优势
• 面向对象的语义
Ice “在线路上”完全保留了 面向对象范型。所有的操作调用都使用迟后绑定,所以操作实现的选定,是根据对象在运行时的(而不是静态的)实际类型决定的。
• 支持同步和异步的消息传递
Ice 提供了同步和异步的操作调用(AMI)和分派(AMD),并且通过IceStorm 提供了发布-订阅消息传递机制。这样,你可以根据你的应用的需要来选择通信模型,而不必把你的应用硬塞进某种模型里。
• 支持多个接口
通过facets,对象可以提供多个不相关的接口,同时又跨越这些接口、保持单一的对象标识。这提供了极大的灵活性,特别是在这样的情况下:应用在发生演化,但又需要与更老的、已经部署的客户保持兼容。
• 机器无关性
客户及服务器与底层的机器架构屏蔽开来。对于应用代码而言,像字节序和填充这样的问题都隐藏了起来。
• 语言无关性
客户和服务器可以分别部署,所用语言也可以不同(目前支持C++、Java、.Net、Object-C、Python、Ruby以及PHP (客户端))。 客户和服务器所用的Slice 定义建立两者之间的接口合约,这样的定义也是它们唯一需要达成一致的东西。
• 实现无关性
客户不知道服务器是怎样实现其对象的。这意味着,在客户部署之后,服务器的实现可以改变,例如,它可以使用不同的持久机制,甚至不同的程序设计语言。
• 操作系统无关性
Ice API 完全是可移植的,所以同样的源码能够在Windows 和UNIX上编译和运行。
• 线程支持
Ice run time 完全是线程化的,其API 是线程安全的。 作为应用开发者,(除了在访问 共享数据时进行同步)你无需为开发线程化的高性能客户和服务器付出额外努力。
• 传输机制无关性
Ice 目前采用了TCP/IP 和UDP 作为传输协议。客户和服务器代码都不需要了解底层的传输机制(你可以通过一个配置参数选择所需的传输机制)。
• 位置和服务器透明性
Ice run time 会负责定位对象,并管理底层的传输机制,比如打开和关闭连接。客户与服务器之间的交互显得像是无连接的。如果在客户调用操作时,服务器没有运行,你可以通过IcePack 让它们随需启动。服务器可以迁移到不同的物理地址,而不会使客户持有的代理失效,而客户完全不知道对象实现是怎样分布在多个服务器进程上的。
• 安全性
通过SSL 强加密,可以使客户和服务器完全安全地进行通信,这样,应用可以使用不安全的网络安全地进行通信。你可以使用Glacier穿过防火墙,实现安全的请求转发,并且完全支持回调。
• 内建的持久机制
使用Freeze,创建持久的对象实现变成了一件微不足道的事情。Ice提供了对高性能数据库Berkeley DB[18] 的内建支持。
• 开放源码
Ice 的源码是开放的。尽管使用Ice 平台,并不一定要阅读源码,但通过源码你可以了 解各种事情是怎样实现的,或把这些代码移植到新的操作系统上。