ZeroC Ice概述

Ice之分布式编程

The Internet Communications Engine(Ice)是一个面向对象的RPC框架,它可帮助您以最小的工作量构建分布式应用程序。其负责与底层网络编程接口的所有交互,使得开发者能够将精力集中在应用程序的逻辑处理上,而无需关心诸如打开网络连接、网络传输数据序列化与反序列化、失败重连等细节的实现。

Ice的主要设计目标是:

  • 提供适合在异构环境中使用的面向对象的RPC框架。
  • 提供一整套功能,支持为各种域开发真实的分布式应用程序。
  • 避免不必要的复杂性,使平台易于学习和使用。
  • 提供有效的网络带宽、内存使用和CPU开销的实现。
  • 提供具有内置安全性的实现,使其适用于不安全的公共网络。

简单来说,Ice的设计目标就是“让我们构建一个强大的中间件平台,让开发人员的生活更轻松。”

Ice概述

Ice体系架构

Ice是一个面向对象的中间件平台。从根本上说,这意味着Ice为构建面向对象的客户端 - 服务器应用程序提供了工具、API和库支持。Ice应用程序适用于以下异构环境下的开发:

  • 客户端和服务端使用不同的编程语言编写。
  • 客户端和服务端在不同的操作系统和机器体系结构上运行,并且可以使用各种网络技术进行通信。

无论部署环境如何,这些应用程序的源代码都是可移植的。

术语
Client与Server

client(客户端)与server(服务器)不是应用程序特定部分的名称; 它们表示的是在请求期间应用程序的某些部分所扮演的角色:

  • 客户端是活动实体。他们向服务器发起服务请求。
  • 服务器是被动实体。他们根据客户端的要求提供服务。

在这里,服务器不是只响应请求而从不发出请求的“纯”服务器。相反,其通常充当某个客户端的服务器,但反过来,又充当了另一个服务器的客户端,以满足这个客户端的请求。

同样的,客户端通常也不是一个只请求服务的“纯”客户端。相反,客户端通常会是客户端+服务器的混合体。例如,客户端可能会在服务器端长时间的进行操作; 在操作开始时客户端可以向服务器提供一个callback回调,这样服务器在操作完成时就可以使用该callback通知此客户端。在这种情况下,客户端在启动操作时充当客户端,在通知操作完成时充当服务器。

这种角色转换在许多系统中很常见,所以通常情况下,Client - Server系统可以更准确地描述为P2P(peer-to-pper)系统。

Ice Object

Ice Object(Ice对象)是一种抽象概念。其通常有以下几个特点:

  • Ice对象是在本地或远程地址空间中可以响应Client端请求的实体。
  • 单个Ice对象可以在单个server中实例化,或者同时在多个server中实例化。即使一个Ice对象实例化多次,它仍然是一个Ice对象。
  • 每个Ice对象都有一个或多个interface接口。接口是一组方法的集合。客户端通过调用这些接口方法操作发出服务请求。
  • 一个接口方法具有零个或多个参数以及返回值。参数和返回值具有特定类型。参数需要被命名并且具有in/out方向性:in方向的参数是指由客户端初始化并传递给服务器;out方向的参数则由服务器初始化并传递给客户端。(返回值只是一个特殊的out方向参数。)
  • Ice对象具有一个独特的interface,称为其主接口。此外,Ice对象可以提供零个或多个辅助接口,称为facets。客户端可以从这些facets中选择他们想要使用的接口来进行通信。
  • 每个Ice对象都有一个唯一的对象标识。它是一个把对象自身从其他对象中区分开来的值。Ice对象模型假定各个对象的标识都是全局唯一,也就是说,Ice通信领域中没有两个对象可以具有相同的对象标识。

实际上,您不需要使用这些全局唯一的对象标识(例如UUID),只需使用那些不与其他标识冲突的标识即可。然而,这就是使用全局唯一标识符所具有的架构上的优势,详细细节我们会另起篇幅讲述。

Proxy

要使客户端能够联系Ice对象,客户端必须拥有Ice对象的一个proxy代理。代理运行于本地客户端的地址空间;它代表了客户端的(也可能是远程的)Ice对象。

代理充当Ice对象的本地特使一样的角色,当客户端调用代理的某个方法时,运行过程如下:

  1. 确定Ice对象
  2. 如果Ice对象指向的服务器没有运行,则激活它
  3. 激活服务器中的Ice对象
  4. 将任何in方向参数(入参)传输到Ice对象
  5. 等待操作完成
  6. 将任何out方向参数(出参)和返回值返回给客户端(或者在发生错误时抛出异常)

代理封装了要执行的这一系列步骤的所有必要信息。特别是,代理包含:

  • 寻址信息,使得客户端运行时能够联系上正确的服务器
  • Ice对象标识信息,用于标识服务器中哪个Ice对象才是请求的目标
  • 可选的facet标识符信息,用于确定Proxy指向了Ice对象的哪个facet接口。
字符串化的Proxy

代理中的信息可以表示为字符串。例如,字符串:

SimplePrinter:default -p 10000

上述是proxy的可读表示。Ice run time提供了API允许您将代理转换为其字符串形式,反之亦然。正因此,这些API可用于将代理存储在数据库表或文本文件中。

如果客户端知道Ice对象的标识信息及寻址信息,则可以通过这些信息“凭空”创建一个代理。换句话说,代理中的任何信息对开发者而言都是透明可见的; 客户端只有知道了一个Ice对象的标识信息、寻址信息和对象类型才能联系上这个Ice对象。

直接代理

直接代理是嵌入了Ice对象标识的代理,其运行于server地址空间。地址完全由以下内容指定:

  • 协议标识符(例如TCP / IP或UDP)
  • 协议的特定地址(例如主机名和端口号)

要联系直接代理表示的Ice对象,Ice run time使用了代理中的寻址信息来联系这个服务器; 客户端发出的每个服务请求都会将这个Ice对象的标识发送给服务器。

间接代理

间接代理有两种类型。它可以仅提供对象的标识,或者它可以与Ice对象适配器标识符一起指定标识。仅使用其标识可访问的对象称为已知对象,相应的代理是众所周知的代理。例如,字符串:

SimplePrinter

上述就是一个已知Ice对象的有效代理,其标识为SimplePrinter。

间接代理包含了一个具有字符串形式的对象适配器标识符。

SimplePrinter@PrinterAdapter

无论该对象是否是一个已知的对象,都可以使用像上述这样的代理来访问对象的适配器。

需要注意的是,间接代理并不包含寻址信息。要找到要连接的服务器,客户端需要将间接代理的信息传递给定位器。这样,定位器就会使用对象标识或对象适配器标识作为键去包含服务器地址的表中查找对应的服务器地址,并将当前服务器地址作为结果返回给客户端。经此以后,客户端就知道如何联系服务器并像往常一样向其发起服务请求。

整个过程类似于域名与其IP地址在DNS服务器中的映射那样:当我们使用域名(例如 www.zeroc.com)浏览网页时,主机名首先被解析为IP地址,一旦知道了对应的IP地址后就用于连接我们要浏览的服务器。对于Ice而言,这种映射关系就变成从对象标识或对象适配器标识符协议地址对,但在其他方面与上述非常相似。客户端知道如何通过配置联系定位器(就像Web浏览器知道如何通过配置使用哪个DNS服务器一样)。

直接与间接绑定

将代理中的信息解析为协议地址对的过程被称之为binding(绑定)。显然,直接绑定用于直接代理,间接绑定用于间接代理。

间接绑定的主要优点是它允许我们移动服务器(即更改其地址),而不会使客户端持有的现有代理无效。换句话说,直接代理可以避免额外查找服务器的开销,但如果将服务器移动到其他机器上则之前的直接代理就会失效。反之对于间接代理,即使我们移动(或迁移)了服务器,其也还会继续工作。

固定代理

固定代理是指绑定到专用连接(不包含寻址信息或适配器名称,而是包含一个连接句柄)的代理。只要连接保持打开,连接句柄就会保持有效,因此,一旦连接关闭,代理将不再起作用(并且将永远不会再次工作)。固定代理不能被封装,也就是说,它不能作为方法调用的参数传递。固定代理用于允许双向通信,因此服务器可以在不必打开新连接的情况下对客户端进行回调。

路由代理

路由代理把所有方法调用转发到一个特殊的目标对象,而非直接发送给实际目标。路由代理对于实现Glacier2等服务非常有用,它使客户端能够与防火墙后面的服务器进行通信。

Replication

在Ice中,Replication使对象适配器(及其对象)在多个地址可用。Replication的目标通常是为分布式服务器环境提供冗余机制。如果环境中某台计算机碰巧发生故障,则其他计算机仍然可用。

Replication的使用意味着应用程序是为它而设计的。这意味着客户端通过某地址访问对象而获得的结果与通过任何其他地址访问获取的结果相同。当然,这并不是说这些对象是无状态的,而是说它们为了保持状态上的一致,被设计成要与数据库进行状态上的同步。

当代理为对象指定多个地址时,Ice支持有限形式的Replication。Ice运行库为其初始化连接尝试随机选择其中一个地址,并在出现故障时尝试所有地址。例如以下这个代理:

SimplePrinter:tcp -h server1 -p 10001:tcp -h server2 -p 10002

此代理指明具有标识符SimplePrinter的对象可通过两个地址之一进行TCP通信,一个是服务器server1,另一个是服务器server2。用户或系统管理员只需要确保这些服务器的指定端口运行了相关的服务即可。

复制组

除了上面描述的基于代理的复制之外,Ice还支持一种更有用的复制形式,称为复制组,需要使用位置服务。

复制组具有唯一标识符,由任意数量的对象适配器组成。一个对象适配器至多可以是一个复制组的成员; 这样的适配器被认为是复制的对象适配器。

复制组被建立之后,复制组的标识符可以在间接代理中用来代替对象适配器的标识符。例如,PrinterAdapters标识符就能作为一个代理像如下所示那样被使用:

SimplePrinter@PrinterAdapters

复制组被位置服务视为“虚拟对象适配器”。当解析一个包含复制组的间接代理时。例如,位置服务可以决定是否返回复制组中所有对象适配器的地址,在这种情况下,客户端Ice运行库可以选择使用了前面讨论的有限复制形式地址之一随机返回。而当使用了探索式算法时位置服务只会返回一个地址。

无论位置服务解析复制组的方式如何,关键优势都是间接性:位置服务作为中间人可以使绑定的过程变得更加智能。

Servants

正如我们所提到的,Ice Object是具有类型、标识符和寻址信息的概念实体。然而,客户端请求最终必须由可以供具体方法调用的服务器来处理。换句话说,客户端请求最终必须在服务器内由代码执行,该代码以特定编程语言编写并在特定处理器上执行。

提供了具体方法调用行为的服务器模块就被称为Servants。Servants为Ice对象提供了实现基础。实际上,Servants只是由服务器开发者编写的类的实例,就类似于注册在服务器Ice运行库上的Ice对象的雇员一样(顾名思义了)。Servants的方法即实现自Ice对象的接口,并提供具体实现。

一个Servants可以化身为一个Ice对象或者同化身为多个Ice对象。如果是前者,这个Ice对象的标识符就隐式的包含在了这个Servants中。如果是后者,则每次请求都要提供Ice对象的标识符,因此,它才可以知道其在请求期间要化身为哪个Ice对象。

相反的,单个Ice对象可以有多个Servants。例如,我们可以为包含不同机器不同地址的Ice对象创建一个代理。在这种情况下,我们将有两个服务器,每个服务器的Servants都指向了同一个Ice对象。当客户端在这样的Ice对象上调用方法时,客户端运行库将请求发送到其中一个服务器。换句话说,单个Ice对象的多个Servants允许您构建冗余系统:客户端运行时尝试将请求发送到一个服务器,如果尝试失败,则将请求发送到第二个服务器。仅当第二次尝试也失败时,才会向客户端应用程序代码报告错误。

至多一次语义

Ice请求具有至多一次语义:Ice运行库尽最大努力将请求传递到正确的目标,并且根据具体情况,可能会重试失败的请求。。Ice保证它将发送请求,或者,如果在无法发送请求给服务器时,则以适当的异常通知客户端; 在任何情况下请求都不会发送两次,也就是说,只有在知道先前的尝试确实失败时才会重试。

此规则的一个例外是UDP传输上的数据报调用。对于这些重复的UDP数据包可能导致其违反了至多一次的语义。

至多一次的语义很重要,因为它们保证可以安全地使用非幂等的操作。幂等操作是这样一种操作,如果执行两次,则具有与执行一次相同的效果。例如,x = 1;是一个幂等操作:如果我们执行两次操作,最终结果就像我们执行一次一样。另一方面,x++就不是幂等的:如果我们执行两次操作,那么最终结果与我们执行过一次的结果不一样。

如果没有至多一次语义,我们可以构建在出现网络故障时更健壮的分布式系统。然而,现实系统需要非幂等操作,所以至多一次语义是有必要的,即使它们在存在网络故障时系统不那么健壮。Ice允许您将单个方法标记为幂等操作。对于此类方法,Ice运行库将使用比非幂等操作更积极的错误恢复机制。

同步方法调用

默认情况下,Ice使用的请求调度模型是一个同步的RPC模型:方法调用的行为类似于本地调用,也就是说,客户端线程在调用期间被挂起,并在调用完成时被唤醒(并且其结果可用)。

异步方法调用

Ice还支持异步方法调用(AMI):客户端可以异步调用方法,这意味着客户端的调用线程在等待调用完成过程中不会被阻塞。客户端传递正常参数,并且根据语言映射,还可能传入一个Callback,当服务器调用完成时回调给客户端运行库;或者此次调用返回一个客户端最终可以获取结果的future任务。

服务器无法区分异步调用和同步调用 - 无论哪种方式,服务器只是看到客户端调用了Ice对象的方法实现。

异步方法调度

异步方法调度(AMD)是AMI的服务器端等价物。对于同步调度(默认),服务器端运行库上行调用服务器中的应用程序代码以响应操作调用。当操作正在执行(或者正在休眠,例如,因为它正在等待数据)时,执行的线程被锁在在服务器中; 该线程仅在操作完成时被释放。

使用异步方法调度,服务器端应用程序代码被告知操作调用何时来到。但是,服务器端应用程序可以选择延迟处理请求,而不是强制立即处理请求,并在通知后释放请求的执行线程。此后服务器端应用程序代码就可以随心所欲地执行其他操作。最终,一旦操作结果出来了,服务器端应用程序代码就会进行API调用,以下行通知服务器端Ice运行库先前调度的请求现已完成; 此时,操作结果将被返回给客户端。

如果服务器需要在某段时间内阻止客户端的操作,则AMD很有用。例如,服务器可能有一个带有get操作的对象,该操作需要从外部异步数据源返回数据,此刻就需要阻塞客户端调用直到此数据可用为止。通过同步调度,正在等待数据到达的客户端会占用服务器中的执行线程。显然使用同步调度方式的客户端不会太多(最多十几二十个)。使用异步调度,则服务端可因某调用而阻塞住成百上千的客户端,而这些被阻塞的客户端不会占用服务器中的任何线程。

同步和异步方法调度对客户端来说都是透明的,也就是说,客户端无法判断服务器是选择同步还是异步处理请求。

单向方法调用

客户端可以单向调用一个方法。单向调用具有“尽力而为”的语义。对于单向调用,客户端运行库将此次调用交给本地传输,并且一旦本地传输出去此次调用,就意味着在客户端调用完成。然后,操作系统异步发送此实际调用。但服务器并不回复单向调用,即调用流程仅从客户端流向服务器,反之亦然。

单向调用是不可靠的。例如,目标对象可能不存在,在这种情况下,调用仅仅是丢失了。类似地,此次调用可能被分发给服务器中的某Servants,但其操作可能失败(例如,因为参数值无效); 如果是这样,客户端不会收到任何出错的通知。

单向调用仅仅存在于那些没有返回值、出参、异常抛出的方法中。

对于服务器端的应用程序来说,单向调用是透明的,也就是说,服务器无法区分来自客户端的双向调用和单向调用。

仅当目标对象提供面向流的传输(例如TCP / IP或SSL)时,单向调用才可用。

请注意,即使单向调用是通过面向流形式的传输,它们也可能在服务器中无序处理。这可能发生的,因为每次调用都是在自己的线程中调度:即使调用时按顺序初始化并到达服务器,这并不意味着它们将按顺序处理 - 线程调度的变幻莫测可能导致某单向调用比其他更早到达的调用先完成。

批量单向方法调用

每次单向调用都会向服务器发送一次单独的消息。对于一系列短消息,这样做的开销很大:客户端和服务器端的运行库必须为每个消息在用户模式和内核模式之间切换,并且在网络传输来说,每个消息都会产生流量的开销,如额外的消息控制和确认。

批处理单向调用允许您将一系列单向调用作为单个消息发送:每次调用批处理单向操作时,方法调用就缓存在客户端运行库。一旦缓存中累积够了你想要发送的所有单向调用,你就可以调用一个可以将这些调用发送出去的单独的API。然后,客户端运行库就将所有缓冲的调用以单条消息形式发送出去,服务器接收这条包含所有调用的消息。这避免了为客户端和服务器反复进入内核的开销,并且在网络上也更容易处理,因为一个大消息可以比许多小消息更有效地传输。

在单向批处理消息中的各个调用在服务器中由单个线程负责调用,这些单向调用将依照其被放入的顺序处理。这保证了服务器可以按顺序处理批量单向消息中的各个操作。

批量单向调用对于消息服务(如IceStorm)非常有用,同时对于那些提供密集set属性方法的接口而言也是有用的。

数据报调用

数据报调用也具有类似于单向调用那样的“尽力而为”的语义。但是,数据报调用要求对象提供UDP协议作为传输基础(而单向调用需要TCP/IP协议)。

与单向调用一样,只有那些没有返回值、出参或异常的方法能进行数据报调用。数据报调用使用UDP协议来调用方法。一旦本地UDP堆栈接收了该消息,该方法就返回; 而实际方法调用则由幕后的网络堆栈异步发送完成。

与单向调用一样,数据报调用是不可靠的:目标对象可能不存在于服务器中,服务器也可能未运行,或者此调用可能在服务器中执行了但由于客户端发送的参数无效而失败。类同单向调用,客户端不会收到此类错误的通知。

但是,与单向调用不同,数据报调用有以下几类错误情形:

  • 单个调用可能是在网络中丢失。这是由于UDP数据包传输的不可靠性。例如,如果按顺序调用了三个方法,则中间调用可能会丢失。(单向调用不会发生这样的事情 - 因为它们是通过面向连接的传输传递的,因此不会丢失单个调用。)
  • 个别调用可能无序到达。同样,这是由于UDP数据报的性质导致的。由于每次调用都是作为单独的数据报发送的,并且各个数据报可能采用不同的网络路径传输,因此调用可能会按照与发送顺序不同的顺序到达。

数据报调用非常适合LAN上的小消息,其中丢失的可能性很小。它们还适用于低延迟比可靠性更重要的情况,例如快速、交互式的互联网应用。最后,数据报调用可用于同时向多个服务器多播消息。

批量数据报调用

同批量单向调用一样,批量数据报调用允许您在缓冲区中累积多个调用,然后通过API调用来刷新缓冲区,将整个缓冲区内容作为单个数据报发送。批量数据报减少了重复系统调用的开销,并使得底层网络更有效率地运行。但是,批量数据报调用仅对总大小基本上不超过网络PDU限制的批处理消息有用:如果批量数据报的大小太大,UDP分段会使一个或多个片段丢失的可能性更大,这将导致丢失整个批量消息。但是,您可以保证批量中的所有调用都将被传递,或者都不被传递。批量消息中的单个调用不可能单独丢失。

批量数据报在服务器中也是使用单个线程来调度各个单向调用的。这保证了调用按照它们发送的顺序进行 - 调用不会服务器中重新排序。

运行时异常

任何方法的调用都可能引发运行时异常。运行时异常由Ice运行库预定义,并涵盖常见错误类型,例如连接失败、连接超时或资源分配失败。运行时异常是作为本地异常出现在应用程序中,因此,其可以与那些支持异常处理的语言的异常处理功能巧妙集成。

用户异常

服务器通过向客户端引发用户异常来指示这个客户端应用程序的错误原因 用户异常可以携带任意数量的复杂数据,并且可以安排到异常继承层次结构中,这使得客户端可以通过捕获继承层次结构中的异常来轻松地处理错误类别。与运行时异常一样,用户异常映射为客户端本地异常。

属性

Ice运行库多数时间都是通过属性来进行配置的。属性是键值对,例如Ice.Default.Protocol=tcp。属性通常存储在文本文件中,并由Ice运行库解析,以配置各种选项,例如线程池大小,跟踪级别和各种其他配置参数。

Slice(Ice的规范化语言)

每个Ice对象都有至少一个包含许多方法的接口。这些用于在客户端和服务器之间通信的接口、方法和数据类型都是使用Slice语言定义的。Slice允许您以独立于特定编程语言(如C ++,Java或C#)的方式定义客户端 - 服务器契约。这些定义好的Slice由编译器编译为特定编程语言的API,也就是说,这部分由特定的接口和类型组成的API是由编译器自动生成的。

语言映射概述

Slice如何被翻译成特定编程语言的规则称为语言映射。例如,对于C ++语言映射而言,一个Slice序列以 std::vector的形式出现,而对于Java映射来说,Slice序列表现为Java数组。为了明确Slice对不同的语言表征,您需要了解Slice及其语言映射的知识与定义。当然,这些映射规则十分简单而且足够常规,您无需阅读生成的代码就可了解如何使用它们。

当然,您也可以研读自动生成的代码。但是,这些生成的代码不一定适合阅读,而是阅读起来也是一个低效的过程。我们建议您熟悉语言映射的规则;这样,您几乎可以忽略掉生成的代码,除非您对代码的某些特定细节感兴趣。

目前,Ice已经为C ++,C#,Java,JavaScript,Python,Objective-C以及客户端PHP和Ruby提供了语言映射。

客户端与服务端结构
ZeroC Ice概述_第1张图片

客户端和服务器都由应用程序代码、lib库和从Slice定义生成的代码混合而成:

  • 客户端和服务端的Ice core部分包含了用于远程通信的lib库。这些代码大部分涉及底层的网络、线程、字节排序以及我们希望隔离于应用程序业务代码的许多其他网络相关问题的细节。Ice core提供了供客户端和服务器使用的许多核心库。
  • Ice core的通用部分(即非Slice语言定义的Ice部分)可通过Ice API访问。您可以使用Ice API管理Ice,例如Ice运行环境的初始化和释放。Ice API对于客户端和服务器来说是相同的(尽管服务器使用的API比客户端多得多)。
  • 代理代码部分是由Slice语言定义自动生成的,因此其由您在Slice中定义的对象类型和数据所决定。代理代码部分有两个主要功能:
    • 它为客户端提供了一个下行接口。通过调用代理API函数可以向服务器发送RPC消息,这个RPC消息最终将调用服务器目标对象上的相应函数。
    • 它提供了代码的编组及解编。编组是序列化复杂数据结构(例如序列或字典)以在线路上传输的过程。编组将数据转换为标准化、独立于本地机器的字节序和填充规则的传输形式。解编与编组相反,即反序列化由网络到达的数据,并以对应于所使用编程语言的方式在本地重建数据结构。
  • Skeleton代码也是从Slice定义生成的,因此其特定于您在Slice中定义的对象类型和数据。Skeleton是对标于客户端代理部分的服务器代码:它提供了一个上行调用接口,以将数据传输到您编写的应用程序线程的控制之下。skeleton也包含了代码的编组和解编,因此服务器可以接收客户端发送的参数,并将参数(出参)或异常返回给客户端。
  • 对象适配器是Ice API的一部分,它存在于服务器端:只有服务器使用到对象适配器。对象适配器有几个功能:
    • 对象适配器将来自客户端的传入请求映射为服务器对象的特定方法。换句话说,对象适配器跟踪了内存中指定对象标识的servants
    • 对象适配器与一个或多个传输端点相关联。如果多个传输端点与适配器关联,servants(适配器中拟人化的Ice对象)就能通过这些端点被访问到。例如,您可以将TCP/IP端点和UDP端点同时与某适配器相关联,以交替性的提供不同质量与性能的服务。
    • 对象适配器负责创建可以传递给客户端的代理。对象适配器知道每个对象的类型、标识和传输细节,并在服务端应用程序请求创建代理时嵌入这些细节信息。

就进程角度而言,此处只涉及了两个进程:客户进程和服务进程。Ice库提供了对分布式通信的所有运行支持,当然,自动生成的代码是由Slice定义的。(对于间接代理,需要定位器解析传输端点以获得对应的代理。)

Ice协议概述

Ice提供了一种RPC协议可以用于各种基础传输。最常见的例子是TCP和UDP传输,但Ice也支持Websocket,蓝牙和Apple的iAP。此外,Ice还允许您使用 SSL来加密客户端和服务器之间的所有通信数据。

Ice协议定义如下:

  • 许多消息类型,例如请求和回复消息类型。
  • 协议状态机,它确定客户端和服务器交换不同消息类型的顺序,以及TCP/IP的相关连接建立和拆除语义。
  • 编码规则,确定各种类型的数据如何在网路上表示。
  • 每种消息类型的表头,包含消息类型、消息大小、使用的协议和编码版本等详细信息。

Ice还支持线路压缩:通过设置配置参数,您可以商定网络流量的压缩以节省带宽。如果您的应用程序在客户端和服务器之间需要交换大量数据,这将非常有用。

Ice协议适用于构建高效的事件转发机制,因为它允许我们在不知道消息的内容细节的情况下转发消息。这意味着消息的传递交换并不需要对消息进行任何解编和重新编组 - 而是简单地将这些消息视为不透明的字节缓冲区来转发。

ICE协议还支持双向操作:如果服务器想向客户端发送消息,则可以通过客户端最初创建连接时传入的callback进行。当客户端位于允许传出连接但不允许传入连接的防火墙之后时,此功能尤其重要。

Ice服务概述

Ice core为分布式应用程序提供了一个复杂的客户端 - 服务器开发平台。然而,实际的应用程序需要的不仅仅是远程处理能力:通常,您还需要诸如按需启动服务器、给客户端分发代理、异步事件的分发、配置应用程序和为应用程序分发补丁等能力。

Ice提供了许多各具特色的服务。这些服务以Ice服务器的形式出现,而您的应用程序相对而言充当客户端的角色。这些服务并非使用了开发人员不知晓的Ice内部隐藏API实现,因此理论上这些服务您可以自己开发出来。但是,将这些服务作为平台的一部分提供,可以让您专注于应用程序开发,而不必首先构建大量基础架构。此外,构建这样的服务并不是一项简单的工作,因此了解什么可以拿之即用而不是重复造轮子是值得的。

IceGrid

IceGrid是Ice定位服务的一种实现,它将间接代理中的符号信息解析为间接绑定的协议地址对。当然,IceGrid所具有的功能众多远不止Ice定位服务一个。

IceGrid的特点如下:

  • 允许您注册那些可以自启服务器:在客户端发出请求之前自启服务器可以不处于运行态,而是在第一个客户端请求到达时按需启动。
  • 提供了一些工具使配置包含多个服务器的复杂应用程序变得容易。
  • 支持复制和负载平衡。
  • 可自动分发和修补服务器的可执行文件和从属文件。
  • 提供一个简单的查询服务,使得客户端可以获取他们感兴趣的Ice对象的代理。
IceStorm

IceStorm是一种可以使客户端与服务端解耦的发布订阅服务。从根本上说,IceStorm充当了事件的分发器角色。发布者将事件发送到IceStorm,然后IceStorm将事件传递给订阅者。通过这种方式,发布者发布的单个事件可以发送给多个订阅者。事件按主题分类,订阅者指定他们感兴趣的主题,只有与订阅者主题匹配的事件才会发送到它。IceStorm服务允许选择不同的服务质量标准,使得开发者可以在应用程序的可靠性和性能之间利弊权衡。

如果您需要将信息分发给大量应用程序组件,那么IceStorm特别有用:典型的例子是拥有大量订户的股票行情应用程序。IceStorm将信息发布者与订阅者分离,并负责待发布事件的重新分配。此外,IceStorm可以作为联合服务运行,也就是说,可以在不同的机器上运行多个服务实例,以将负载的处理分散到多个CPU上。

IcePatch2

IcePatch2是一个软件修补服务。它允许您轻松地将软件更新包分发给客户端。客户端只需连接到IcePatch2服务器并请求特定应用程序的更新。该服务自动检查客户端软件的版本,并以压缩格式下载应用程序的组件更新包以节省带宽。还可以使用Glacier2服务加强软件补丁安全性,以确保只有经过授权的客户端才能下载软件更新包。

Glacier2

Glacier2是Ice防火墙穿越服务:它允许客户端和服务器通过防火墙进行安全通信,而不会影响安全性。客户端-服务器的通信使用公钥证书进行SSL双向加密。Glacier2支持相互身份验证以及安全会话管理。

IceBridge

IcerBridge充当一个或多个客户端和服务器之间的桥梁的角色,并尽可能做到透明。

Ice架构的特点

Ice架构为应用程序开发人员提供了许多好处:

  • 面向对象的语义。Ice完全保留了“跨线”的面向对象模式。所有调用方法都使用后期绑定,因此可以根据Ice对象的实际运行需要(即非静态)来选择方法的实现。
  • 支持同步和异步调用。Ice为方法调用和调度提供了同步和异步两种方式,就如同消息发布订阅系统IceStorm那样。它允许您根据应用程序的需要来选择通信方式,而不必使应用程序始终只适用于单个通信方式。
  • 支持多接口。通过使用facet,对象可以提供多个不相关的接口,同时在这些接口上保留同一个对象标识。这提供了极大的灵活性,特别是随着应用程序的发展,但需要与已部署的旧版本客户端程序保持兼容。
  • 机器的独立性。客户端和服务器帮助开发者屏蔽了底层机器架构的特性。应用程序不需要关心诸如字节排序和填充等问题。
  • 语言的独立性。客户端和服务器可以使用不同的编程语言独立开发。客户端和服务器使用的Slice定义建立了它们之间的接口契约,并且这是它们唯一需要达成一致的东西。
  • 实现的独立性。客户端不需要关心服务器如何实现其对象。这意味着可以在部署客户端之后,可以更改服务器的实现,例如,使用不同的持久性机制或甚至更改成与之前不同的编程语言。
  • 操作系统的独立性。Ice API是完全可移植的,因此相同的源代码在Windows和Unix下编译和运行。
  • 线程支持。Ice运行库是完全线程化的,API是线程安全的。应用程序开发人员不需要任何努力(除了同步访问共享数据之外)去开发线程化的、高性能的客户端和服务器。
  • 传输独立性。Ice支持TCP / IP,UDP,蓝牙和iAP。客户端和服务器都不需要关心底层如何传输。(当然,可以通过配置参数选择所需的传输方式。)
  • 位置和服务器的透明度。Ice运行库负责定位对象和管理底层传输机制,例如打开和关闭连接。感知客户端和服务器之间的交互有无连接。通过IceGrid,如果服务器在客户端调用方法时还未运行,则可以安排按需启动服务器。可以将服务器迁移到不同的物理地址,而不会破坏客户端所拥有的代理,并且客户端完全不需知道Ice对象是如何分布在服务器进程上的。
  • 安全性。通过SSL加密完全可以保证客户端和服务器之间通信安全,因此应用程序可以使用那些不安全的公共网络来就可以安全的通信。通过Glacier2,您可以通过防火墙实现请求的安全转发,并完全支持回调。

你可能感兴趣的:(中间件,安卓)