请求---应答协议 - nlp data server

Download Report

Transcript 请求---应答协议 - nlp data server

分布式系统
Distributed Systems
第 4 讲 远程调用
LECTURE 4 REMOTE INVOCATION
王晓阳、张 奇
复旦大学 计算机科学技术学院
1
4.1 目录
Applications
This chapter
(and Chapter 6)
Remote invocation, indirect communication
Underlying interprocess communication primitives:
Middleware
layers
Sockets, message passing, multicast support, overlay networks
UDP and TCP
Figure 5.1 Middleware layers
2
目录
4.1 简介
4.2 请求---应答协议
4.3 远程过程调用
4.4 远程方法调用
4.4.1 RMI的实际问题
4.4.2 RMI的实现
4.4.3 分布式无用单元收集
4.3.1 RPC的设计问题
4.3.2 RPC的实现
4.3.3 实例研究:Sun RPC
4.5 实例研究:Java RMI
4.5.1 创建客户和服务器程序
4.5.2 Java RMI的设计和实现
4.6 小结
3
4.1 简介
远程过程调用范型
◦ 请求---应答协议,描述了一个基于消息传递的范型,支持在客户/服务器
计算中遇到的消息双向传输
◦ 远程过程调用(RPC),将传统的过程调用模型扩展到分布式系统中。
允许客户程序透明地调用在服务程序中的过程。
◦ 远程方法调用(RMI),基于对象的编程模型扩展,允许不用进程运行
的对象通过其彼此通信。是对本地方法调用的扩展。
4
4.2 请求---应答协议
这种通信设计用于支持典型客户/服务器交互中任务和信息的交换
通常情况下,请求---应答通信是同步的,在来自服务器端的应答到
达之前客户端进程是阻塞的。从服务器端的应答是对客户端进程的
有效确认,因此也是可靠的。
异步的请求---应答通信是可选的,这种方式在客户允许检索应答延
迟的情况下是有用的(7.5.2节)。
客户---服务器交换的实现通常采用TCP流的形式,在接下来的客户--服务器交换实现是通过Java UDP数据报API中的send和receive操作描
述的。
5
4.2 请求---应答协议
该协议基于三个通信原语:doOperation, getRequest, sendReply
Figure 5.2 Request-reply communication
6
4.2 请求---应答协议
public byte[] doOperation (RemoteRef s, int operationId, byte[] arguments)
sends a request message to the remote server and returns the reply.
The arguments specify the remote server, the operation to be invoked and the
arguments of that operation.
public byte[] getRequest ();
acquires a client request via the server port.
public void sendReply (byte[] reply, InetAddress clientHost, int clientPort);
sends the reply message reply to the client at its Internet address and port.
Figure 5.3 Operations of the request-reply protocol
7
4.2 请求---应答协议
messageType
int (0=Request, 1= Reply)
requestId
int
remoteReference
RemoteRef
operationId
int or Operation
arguments
array of bytes
Figure 5.4 Request-reply message structure
8
4.2 请求---应答协议
消息标识符
◦ 如果需要提供类似于可靠消息传递或请求—应答通信等额外特性,那么
任何消息管理方案都会要求每一个消息必须有唯一的消息标识符。通过
消息标识符才可以引用消息。
◦ 消息标识符有两部分组成
◦ requestID,发送进程从一个长度不断增加的整数序列获取requestID;
◦ 发送者进程的标识符,如它的互联网地址和端口号
9
4.2 请求---应答协议
请求---应答协议的故障模型
◦ 如果doOperation,getRequest,sendReply三个原语操作基于UDP实现,
那么它们会遇到相同的通信故障:
◦ 存在遗漏故障
◦ 没有保证消息按照其发送顺序进行传输
◦ 除此之外,还会遇到进程故障问题
◦ 考虑到服务器故障或请求、应答消息被丢弃的情况,doOperation方法在
等候获取服务器应答消息时应使用超时(Timeout)
10
4.2 请求---应答协议
超时
◦ 超时发生时,doOperation方法有很多种选择。
◦ 最简单的选择是立即返回给客户一个doOperation发生故障的标示
◦ 超时原因可能是请求或应答消息丢失
◦ 为了避免消息丢失的可能性,doOperation通常会重复发送请求消息直到
它收到应答,或已有理由相信延迟是由于服务器未作回答而不是丢失了
消息。最终,当doOperation返回时,会以未接收到结果的异常告诉客户。
11
4.2 请求---应答协议
丢弃重复的请求消息
◦ 当请求消息重复传输时,服务器可能不止一次地接收到该消息。
◦ 为了避免该情况,协议设计能识别带有相同请求标识符的连续消息,并
过滤掉重发消息。如果服务器还没有发送应答消息,就无须采取特殊行
动,在执行完这个操作时传输该应答。
12
4.2 请求---应答协议
丢失应答消息
◦ 如果服务器收到一个重复的请求消息时已经发送了应答消息,那么除非
它保存了原先的执行结果,否则它需要再次执行这个操作来获得该结果。
◦ 幂等操作(idempotent operation)指的是,它重复执行的效果与它好像
仅执行一次的效果相同。
◦ 例如:给集合添加一个元素是幂等操作,而给序列添加一个元素就不是幂等操作了。
◦ 如果服务器上的操作都是幂等操作,那么就没有必要采取特殊措施来避
免操作的多次执行
13
4.2 请求---应答协议
历史
◦ 对于要求重新传输应答而不需要重新执行操作的服务器来说,可以使用
历史。
◦ 历史,指的是包含已发送的(应答)消息记录的结构
◦ 历史的内容包含请求标识符、消息和消息被发送到的客户标识符。
◦ 其目的是当客户进程请求服务器时让服务器重新传输应答消息
◦ 和历史相关的问题是它的内存开销
◦ 由于客户每次只能发送一个请求,服务器可以将每个请求解释成客户对
上一次应答消息的确认。因此,历史中只需要包含发送个每个客户的最
晚的应答消息。
14
4.2 请求---应答协议
交互协议的类型
◦ 为了实现多种类型的请求行为,可以使用三种协议。每种协议在出现通
信故障时会产生不同的行为。
◦ 请求(R)协议
◦ 请求—应答(RR)协议
◦ 请求—应答—确认应答(RRA)协议
Figure 5.5 RPC exchange protocols
15
4.2 请求---应答协议
R协议中,客户端向服务器端发送一个单独的请求消息,这个协议
可以用在不需要从远程操作返回值或客户端不需要得到远程操作执
行确认的情况中。在发送请求后,客户端可以立即继续执行,而无
须等待应答消息。
RR协议,对于绝大多数客户/服务器的交互是有用的,因为它是请
求—应答协议的,不要求特殊的确认消息,服务器的应答消息可以
看成客户端请求的确认。随后客户端的调用,可以视为服务器应答
消息的确认。因UDP包丢失而引起通信故障可以通过带有重新过滤
的请求传输和重新传输进行屏蔽。
16
4.2 请求---应答协议
RRA协议基于三种消息的交互:请求---应答---确认应答。确认应答
消息中包含了来自于应答消息的requestID。服务器可以利用这个ID
来从历史中删除相应的条目。
对于到达的确认消息中的requestID来说,它可以看成所有requestID
中比其更小的应答消息的确认。因此部分确认消息丢失也不会造成
影响。
尽管该交互过程涉及附加的消息,也无须阻塞客户端进程,因为该
确认可能在想客户端发送应答之后才传输的。
17
4.2 请求---应答协议
请求—应答协议的TCP流使用
◦ 在请求—应答协议中,服务器用缓冲区来接收请求消息,客户端用缓冲
区来接收应答消息。
◦ 过程的参数和结果可能是任意长度的,所以数据报长度的限定(通常为
8Kb)不适用于透明RMI或RPC系统使用。
◦ 实现基于TCP流的请求—应答协议的原因之一是期望避免实现多包协议,
因为TCP流可以传输任意长度的参数和结果。
◦ 如果使用TCP协议,就能保证可靠的传输请求消息和应答消息,请求—
应答协议就没有必要去处理消息的重传、重复消息过滤、历史使用等问
题。流控机制也可以传递大量的参数和结果而不需采用特殊措施来避免
大规模的接收。
18
4.2 请求---应答协议
TCP协议可以简化请求—应答协议的实现。
如果同一对客户/服务之间基于同一个流连续发送相同的请求—应
答消息,也不需要在每次远程调用上都有连接开销。
如果应用不需要使用TCP提供的所有机制,那么更有效的方法是定
制一个基于UDP实现的协议。
◦ 例如,SUN NFS在客户、服务器之间传输固定长度的文件块,不需要提
供发送无限长消息的支持。此外,操作设计成幂等操作,重传丢失的应
答消息而多次执行操作也没关系。
19
4.2 请求---应答协议
HTTP:请求—应答协议的例子
◦ Web服务器有两种不同的实现管理资源的方法:
◦ 数据,如HTML网页的正文或图片或面板的类
◦ 程序,如Servlets或PHP或运行在Web服务器端的Python程序
◦ 客户端请求指定一个包含Web服务器上的DNS主机名和Web服务器上选
择端口的URL和在该服务器上资源的标识符。
◦ HTTP协议指定一个消息,该消息涉及:
◦ 请求—应答交互、方法、参数、结果及将它们的编码规则
◦ 支持一个固定的方法集合(GET,PUT,POST等)
◦ 准许内容协商和密码式验证
20
4.2 请求---应答协议
HTTP:请求—应答协议的例子
◦ 内容协商(content negotiation):客户端请求中包含说明他们能够接受
的数据表示形式的信息,是服务器能选择出对于客户端最合适的数据表
示形式
◦ 认证(authentication):凭据(credential)和质询(challenge)用于密
码式验证,试图去访问受密码保护的区域时,服务器的应答包含了适用
于资源的质询,当客户端接收到质询,它令用户输入用户名和密码,并
提交与后续请求关联的凭据。
21
4.2 请求---应答协议
HTTP基于TCP实现,协议初始版本中,客户/服务器交互由下列步骤
组成:
◦ 客户端请求(连接),服务器在一个默认端口或URL指定的端口接受连
接
◦ 客户端向服务器发送请求消息
◦ 服务器向客户端发送应答
◦ 连接断开
每个请求—应答交互都建立、断开连接的代价高昂,引起太多的消
息通过网络发送。注意:浏览器一般会向相同的服务器发送多个请
求。
22
4.2 请求---应答协议
HTTP 1.1中,使用持久连接来获取页面中的图片。
◦ 持久连接中,客户/服务器维持一系列的请求—应答交互,可以在任何时
候通过客户端或服务器端向另一个参与者发送指示来断开一个持久连接。
◦ 如果服务器有一段时间处于空闲状态,那么该持久连接将会断开。
请求和应答以ASCII字符串的形式被编码进消息。
资源被表示成字节序列的形式并可能被压缩。
资源在参数和结果中具有类似MIME结构
◦ 多用途Internet邮件扩展(Multipurpose Internet Mail Extension)是发送
多部分数据(邮件中的文本、图片、声音)的标准。
◦ 数据源可以提供参数和结果中类似MIME的结构。
◦ 数据以MIME结构为前缀,接收者可以知道如何处理它。
23
4.2 请求---应答协议
HTTP方法
◦ 每个用户请求指定使用服务器资源的方式和该方法的URL
◦ 应答则说明该请求的状态
◦ 请求和应答也可能包含资源数据、表单内容或者运行在Web服务器上的
程序资源输出。该方法包含以下内容:
◦ GET
◦ HEAD
◦ POST
◦ PUT
◦ DELETE
◦ OPTIONS
◦ TRACE
24
4.2 请求---应答协议
HTTP方法
◦ GET:请求在参数中给出的URL对应的资源
◦ 如果URL指向数据,那么服务器就会返回该URL指定的数据
◦ 如果URL指向一个程序,那么服务器就会运行该程序并把结果返回客户端
◦ URL中也可以包含参数,例如:GET方法能够将表单的内容以程序参数的形式发送出去
◦ HEAD:请求和GET相同,但是不返回任何数据
◦ 仅返回与数据相关的信息,例如最后一次修改的时间,数据格式和大小。
◦ POST:指定资源(如程序)的URL,该资源可以处理请求消息体中提供的数据
◦ 执行数据的处理过程与URL所指定的程序功能相关。
◦ 当某个执行活动可能改变服务器端的数据时使用POST方法。
◦ POST方法可以处理:
◦ 向数据处理过程提供数据
◦ 发布消息到邮件列表或更新别表成员的详细信息
◦ 通过追加操作扩展数据库
25
4.2 请求---应答协议
HTTP方法
◦ PUT:要求请求中提供的数据在存储时以指定的URL作为标识符,要么作为现有资源的修
改,要么作为一种新资源。
◦ DELETE:服务器删除给定URL所标识的资源,服务器可能不经常允许该操作,在这种情况
下将返回请求失败的应答。
◦ OPTIONS:服务器提供给客户端能够应用到给定URL及其特定需求的方法列表(例如GET、
HEAD、PUT)
◦ TRACE:服务器返回请求的消息,用于诊断的目的。
◦ PUT和DELET是幂等操作。但是POST操作未必是这样。
◦ 代理服务器可能中断上面描述的请求,也可能缓存对GET和HEAD的应答
26
4.2 请求---应答协议
HTTP方法
◦ 消息的内容
◦ Request消息指定方法的名称、资源URL、协议的版本、一些头和消息体的选择信息
method
GET
URL or pathname
//www.dcs.qmw.ac.uk/index.html
HTTP version
headers
message body
HTTP/ 1.1
Figure 5.6 HTTP request message
◦ 对代理服务器的请求需要绝对URL
◦ 对源服务器(资源所在服务器)的请求指定路径名,并在主机字头段中给出该源服务器的
DNS名,例如:
GET /index.html HTTP/1.1
Host: www.dcs.qmul.ac.uk
27
4.2 请求---应答协议
HTTP方法
◦ 消息的内容
◦ 通常在字头段中包含了请求的修饰符和客户信息
◦ 例如:最近一次修改资源的时间或者能接收的消息的内容(例如HTML文本、音频等)
◦ 授权字段可用于提供客户的凭证,以证书的形式指定其访问资源的权限
◦ 应答消息指定协议的版本、状态代码和“原因”、一些头信息和可选的消息体
Figure 5.7 HTTP Reply message
◦ 状态代码和原因提供服务器成功的报告,以其他方式执行的请求:前者是由程序解释的
三位数整数,后者是人们能够理解的正文短语。
◦ 头字段中通常传递关于服务器或访问资源的额外信息。
◦ 请求或应答消息体中包含了请求中指定的URL的相关数据信息。
28
4.3 远程过程调用
远程过程调用(RPC)是分布式计算的重大突破,使得分布式编程
和传统编程相似,即实现了高级的分布透明性。
将传统的过程调用模型扩展到分布式环境方式实现。
在RPC中调用远程机器上的程序就像这些程序在本地的地址空间中
一样。
底层RPC系统隐藏了分布式环境重要的部分,包括对参数和结果的
编码和解码、消息传递以及保留过程调用要求的语义。
该概念由Birrell和Nelson在1984年首次提出
29
4.3.1 RPC的设计问题
在介绍RPC系统实现之前,我们首先对下面三个问题进行介绍:
1. RPC的编程风格---接口编程
2. 和RPC关联的调用语义
3. 透明性的关键问题和它如何与远程过程调用相关联
30
4.3.1 RPC的设计问题
接口编程
◦ 大多数现代编程语言提供了把一个程序组织成一系列能彼此通信的模块
的方法。
◦ 模块间的通信可以依靠模块间的过程调用,或者直接访问另一个模块中
的变量来实现。
◦ 为了控制模块之间可能的交互,必须为每一个模块定义显式的接口,模
块接口指定可供其他模块访问的过程和变量。
◦ 实现后的模块隐藏了除接口之外的所有信息。只要模块接口保持相同,
模块的实现就可以随意改变而不影响模块的使用。
31
4.3.1 RPC的设计问题
接口编程
◦ 分布式系统的接口
◦ 在分布式程序中,模块能够运行在不同的进程中
◦ 在客户/服务器模型中,每个服务器提供一个客户端可用的方法集合
◦ 例如:文件服务器能够提供读、写文件的方法
◦ 服务接口(Service Interface)涉及服务器提供的过程的说明、定义每个过程参数的格式
◦ 在分布式编程中,使用接口有很多好处
◦ 对于任何形式的模块化编程,程序员只需要关系服务接口提供的抽象而不需要求关注它
们的实现细节
◦ 程序员无需知道实现服务的语言和底层平台
◦ 只要接口保持不变,实现可以改变,自然的支持软件的演化
32
4.3.1 RPC的设计问题
接口编程
◦ 分布式系统的接口
◦ 接口的定义受分布式底层的基础设施的影响
◦ 运行在某个进程的客户模块去访问另一个进程中模块的变量是不可能的。
◦ 本地过程调用使用参数传递机制,不适用于调用者和过程在不同进程中的情况。
◦ 不支持引用的传递。
◦ 当某个参数同时作为输入/输出参数时,在请求和应答消息中都必须传送它的值。
◦ 本地和远程模块的另外一个不同是,一个过程的内存地址对于一个远程过程是无效的。
◦ 内存地址不能作为参数和远程模块的调用结果返回
◦ 这些约束对于接口规范的定义语言有很重要的影响
33
4.3.1 RPC的设计问题
接口编程
◦ 接口定义语言(Interface definition languages, IDL)
◦ RPC机制可以集成到某种编程语言中,只要该语言包含适当的定义接口的表示法,并准许
将输入和输出参数映射成该语言中正常使用的参数。当一个分布式应用的所有部分都是用
同一种语言编写时,该方法非常有效。然而,准许程序支持各种语言进行编写是十分有益
的。
◦ 接口定义语言,准许以不同语言实现过程以便相互调用。
◦ IDL中提供了一种定义接口的表示法,接口中操作的每个参数可以在类型声明之外附件输
入或输出类型说明
// In file Person.idl
struct Person {
string name;
string place;
long year;
};
interface PersonList {
readonly attribute string listname;
void addPerson(in Person p) ;
void getPerson(in string name, out Person p);
long number();
};
Figure 5.8 CORBA IDL example
34
4.3.1 RPC的设计问题
RPC调用语义
◦ 4.2节讨论了请求—应答协议,说明了可以通过不同的方法来实现
doOperation以提供不同的传输保证,主要选择有:
◦ 重发请求消息
◦ 是否要重发请求消息,直到接收到应答或者认定服务器已经出现故障
◦ 过滤重复消息
◦ 当启用重传请求的时候,是否要在服务器过滤掉重复的请求
◦ 重传结果
◦ 是否要在服务器上保存结果消息的历史,以便无须重新执行服务器上的操作就能重传丢
失的结果
◦ 这些选择组合使用便导致了调用者所见到的远程调用可靠性的各种可能
语义。
35
4.3.1 RPC的设计问题
RPC调用语义
◦ RPC调用语义如下:
◦ 或许调用语义:远程方法可能执行一次或者根本不执行
◦ 故障类型:遗漏故障、系统崩溃
◦ 对可以接受偶然调用失败的系统是有用的
◦ 至少一次调用语义:调用者可能收到返回结果,也可能收到一个异常。收到返回结果的情
况下,调用者知道该方法至少执行过一次
◦ 屏蔽了调用或结果消息的遗漏故障
◦ 故障类型:包含远程对象服务器故障、随机故障
◦ 至多一次调用语义:调用者可能收到返回结果,也可能收到一个异常。
◦ 收到返回结果的情况下,调用者知道该方法恰好执行过一次
◦ 异常信息则是通知调用者没有收到执行结果
36
4.3.1 RPC的设计问题
RPC调用语义
Figure 5.9 Call semantics
注意:本地方法调用的语义是恰好一次
37
4.3.1 RPC的设计问题
透明性
◦ Birrell和Nelson致力于使远程过程调用与本地过程调用尽可能相似
◦ 使得本地过程调用和远程过程调用的语法上没有差别
◦ 所有对编码和消息传递过程的必要调用都要对编写调用的程序员隐藏
◦ 尽管请求消息可能在超时后重发,但这也要对调用者而言是透明的
◦ RPC致力于为过程调用提供位置和访问透明性。
◦ 中间件还能给RPC提供额外程度的透明性
◦ 远程调用比本地调用更容易失败
◦ 涉及网络、另一台计算机、另一个进程
◦ 不论哪种调用语义,总有可能收不到结果
◦ 出故障的情况下,不能判别故障源于网络失效还是服务器进程故障
38
4.3.1 RPC的设计问题
透明性
◦ 远程过程调用的延迟要比本地调用的延迟大好几个数量级
◦ 利用远程过程调用需要把延迟因素考虑进去
◦ 例如:尽可能减少远程交互等
◦ 远程调用也要求另外的参数传递
◦ RPC不支持引用调用
◦ Waldo等认为,本地对象和远程对象的不同应该表现在远程接口上
◦ IDL的设计者也会面临远程调用是否应该透明的抉择
◦ 在有些IDL中,当客户不能与远程过程通信时,远程调用就会抛出一个异常。客户程序应
当能够处理这一异常,并解决此类故障。
◦ IDL也可以提供一种指定过程的调用语义的机制
39
4.3.2 RPC的实现
client process
server process
Request
client stub
procedure
client
program
Communication
module
Reply
server stub
procedure
Communication
dispatcher
module
service
procedure
Figure 5.10 Role of client and server stub procedures in RPC
40
4.3.3 实例研究:SUN RPC
Sun RPC
◦ 为Sun NFS(Sun 网络文件系统)中的客户—服务器通信而设计
◦ 有时也称为ONC(Open Network Computing,开放网络计算)RPC
◦ 做为Sun和其他UNIX操作系统的一部分提供,并且也可以安装在NFS中
◦ 可以用UDP也可以用TCP实现
◦ 当Sun RPC采用UDP时,请求消息和应答消息的长度被限制在一定范围内
◦ 使用至少一次调用语义,广播型RPC是可选的
◦ 提供XDR接口语言和一个可以用于C编程语言的接口编译器rpcgen
41
4.3.3 实例研究:SUN RPC
接口定义语言
◦ Sun XDR最初用于指明外部数据表达,现在扩展成为一种接口定义语言
◦ 通过指定一组过程定义并支持类型定义,XDR可用于定义Sun RPC服务接
口
◦ 与CORBA IDL或Java所使用的接口定义语言相比,表示方法简单
◦ 大多数语言允许指定接口名,Sun RPC提供一个程序号一个版本号
◦ 一个过程定义指定一个过程签名和一个过程号
◦ 只允许使用单个输入参数,需要多个参数的过程必须把参数作为一个结构的组成部分
◦ 过程的输出参数以单个结果返回
◦ 过程签名由结果类型、过程名和输入参数的类型组成
42
Figure 5.11
Files interface in Sun XDR
const MAX = 1000;
typedef int FileIdentifier;
typedef int FilePointer;
typedef int Length;
struct Data {
int length;
char buffer[MAX];
};
struct writeargs {
FileIdentifier f;
FilePointer position;
Data data;
};
struct readargs {
FileIdentifier f;
FilePointer position;
Length length;
};
program FILEREADWRITE {
version VERSION {
void WRITE(writeargs)=1;
Data READ(readargs)=2;
}=2;
} = 9999;
Instructor’s Guide for Coulouris, Dollimore, Kindberg and Blair, Distributed Systems: Concepts and Design Edn. 5
© Pearson Education 2012
43
1
2
4.3.3 实例研究:SUN RPC
接口定义语言
◦ 提供了用于定义常量、类型预定义(typedef)、结构、枚举类型、联合
和程序的表示法。
◦ 类型预定义、结构和枚举类型使用C语言语法。
◦ 可以使用接口编译器rpcgen根据接口定义生成以下部分:
◦ 客户存根过程
◦ 服务器main过程、分发器和服务器存根过程
◦ 用户分发器、客户与服务器存根过程的XDR编码和解码过程
44
4.3.3 实例研究:SUN RPC
绑定
◦ Sun RPC在每台计算机上的一个固定的端口上运行一个称为端口映射器
的本地绑定服务。
◦ 端口映射器的每个实例记录正在本地运行的每个服务所使用的程序号、版本号和端口号
◦ 当服务器启动时,它在本地端口映像器中注册其程序号、版本号和端口号
◦ 当客户启动时,它通过发送指定程序号和版本号的远程请求给服务器主机上的端口映射器,
从而找到服务器的端口
◦ 当一个服务有多个实例运行在不同计算机上的时候,每个实例可以使用
不同的端口号接收客户的请求。
◦ 如果一个客户需要组播一个请求给所有使用不同端口号的服务实例,它
不能使用直接广播消息。解决办法是,客户以组播的方式发送远程过程
调用,将指定程序和版本号的请求广播到所有的端口映像器。每个端口
映像器判断如果有合适的本地服务程序,则给它转发这样的调用。
45
4.3.3 实例研究:SUN RPC
认证
◦ Sun RPC请求和应答消息提供了一个附加域,以便在客户和服务器之间
传输认证信息。
◦ 请求消息中包含正在运行的客户程序的用户证书
◦ 按照UNIX的认证风格,证书包括用户的uid和gid
◦ 访问控制机制构建在认证信息之上
◦ 服务器程序负责实施访问控制,根据认证信息决定是否执行每个过程调
用
◦ 例如:验证用户是否有足够权限来执行所请求的文件操作
46
4.3.3 实例研究:SUN RPC
认证
◦ Sun RPC支持几种不同的认证协议,包括:
◦ 没有认证
◦ UNIX的认证风格,证书包括用户的uid和gid
◦ 为标记RPC消息创建共享密钥的风格
◦ Kerberos认证风格
◦ RPC头部的一个域指明它使用的风格
47
4.4 远程方法调用
远程方法调用(Remote Method Invocation,RMI)
◦ 与RPC紧密联系,RMI扩展到了分布式对象的范畴
◦ 访问对象能够调用位于潜在的远程对象上的方法
◦ RPC和RMI的共性如下:
◦ 都支持接口编程
◦ 都是典型的基于请求—应答协议构造的,并提供一系列如最少一次、最多一次调用语义
◦ 都提供相似程度的透明性
◦ RMI的特殊性:
◦ 程序员能够在分布式系统软件开发中使用所有面向对象编程的功能
◦ 基于面向对象系统中对象标识的概念,在基于RMI系统中的所有对象都有唯一的对象引用
48
4.4.1 RMI的设计问题
RMI在接口编程、调用语义和透明性水平上会遇到与RPC一样的问题
关键设计问题还涉及对象模型,尤其是实现从对象到分布式对象的
转变
本节中将首先描述传统的对象模型,然后描述分布式对象模型
49
4.4.1 RMI的设计问题
对象模型
◦ 一个面向对象程序由相互交互的对象的集合组成,其中每个对象又由一
组数据和一组方法组成。
◦ 一个对象和其他对象通信是通过调用其他对象的方法、传递参数和接收
结果进行的。
◦ 对象能够封装它们的数据和方法代码
◦ 一些语言中,允许程序员定义其实例变量能被直接访问的对象
◦ 一个分布式对象系统中,对象的数据仅通过它们的方法访问
50
4.4.1 RMI的设计问题
对象模型
◦ 对象引用:通过对象引用访问对象
◦ 例如:在Java中,一个变量看上去拥有一个对象,其实它只拥有对该对象的引用。
◦ 为了调用对象的一个方法,需要给出对象引用和方法名,以及必要的参数。
◦ 对象引用是第一类值(first class value),这意味着它们可以赋给变量,也可以作为参数传
递或作为方法的结果返回。
◦ 接口:在无须指定其实现的情况下,提供一系列方法基调的定义(即参
数类型、返回值和异常等)。
◦ 如果类包含实现接口的方法和代码,那么对象将提供该特定的接口。
◦ 在Java中,一个类可以实现几个接口,而一个接口也可以由任意类实现
◦ 接口还可以定义用于声明参数类型或变量类型及方法返回值的类型
◦ 注意:接口没有构造函数
51
4.4.1 RMI的设计问题
对象模型
◦ 动作:在面向对象程序中,动作由调用另一个对象的方法的对象启动。
◦ 调用可以包含执行方法所需的附加信息(参数)。
◦ 接收者执行适当的方法,然后将控制返回给调用对象,有时候会提供一个结果。
◦ 方法的调用会产生三个结果:
◦ 接收者的状态会发生改变
◦ 可以实例化一个新的对象
◦ 可能会在其他对象中发生其他方法调用
◦ 因为调用可能导致其他对象对方法的调用,所以动作就是一连串相关的方法调用,每个调
用最终都会返回。
52
4.4.1 RMI的设计问题
异常
◦ 程序可能会遇到各种错误和无法预计的严重情况
◦ 在方法执行期间,会发现许多不同的问题,例如:对象变量值不一致,无法读取写入文件
或网络套接字等
◦ 程序员需要在他们的代码中插入测试语句以处理所有不常出现的情况或
出错情况,但会降低正常情况下的代码可读性。
◦ 利用异常,可以在不使代码复杂化的情况下清晰处理错误条件。
◦ 每个方法的标题都清楚地列出了所产生异常的条件,以便使用方法的用
户去处理它们。
◦ 可以定义一块代码,以便在某种不期望发生的条件或错误出现的时候抛
出异常。这意味着要将控制传递给另一块用于捕获异常的代码。控制不
会再返回到抛出异常的地方。
53
4.4.1 RMI的设计问题
无用单元收集
◦ 当不再需要对象时,有必要提供一种手段释放其占用空间。
◦ 有的语言可以自动检测出什么时候该收回一个已经不再访问的对象占据
的空间,并将此空间分配给其他对象使用。这个过程称为无用单元收集。
◦ 有的语言不支持无用单元收集,那么程序员必须自己处理释放分配给对
象的空间的问题。这也是一个主要的出错源。
54
4.4.1 RMI的设计问题
分布式对象
◦ 对象的状态由他的实例变量组成。
◦ 在基于对象的范型中,程序的状态被划分为几个单独的部分,每个部分
都与一个对象关联。因为基于对象的程序从逻辑上划分的,所以在分布
式系统中可以很自然地将对象物理地分布在不同的进程或计算机中。
◦ 分布式对象系统可以采用客户---服务器体系结构
◦ 对象由服务器管理,它们的客户通过远程方法调用来调用它们的方法
◦ 在RMI中,客户调用一个对象方法的请求以消息的形式传送到管理该对象的服务器,通过
在服务器端执行对象的方法来完成该调用,并将处理的结果通过另一个消息返回给客户。
◦ 考虑到会有一连串的相关调用,服务器中的对象也可以成为其他服务器中对象的客户。
◦ 分布式对象也可以采用其他体系结构模型。
◦ 例如:为了获得良好的容错性并提高性能,可以复制对象。
◦ 又比如,为了改善性能和可用性,可以迁移对象。
55
4.4.1 RMI的设计问题
将客户和服务器对象分布在不同的进程中,可以提高封装性。
◦ 一个对象的状态只能被该对象的方法访问,这意味着不可能让未经授权
的方法作用于该对象状态
◦ 例如,不同计算机上的对象可能会并发RMI,这意味着可能会并发的访问一个对象,也可
能出现访问冲突。然而,对象的数据只能由其自己的方法访问这一事实允许对象提供保护
自身不遭受不正确访问的方法。
将分布式程序的共享状态视为一个对象集的另一个好处是,对象可
以通过RMI访问,如果类是本地实现的话,那么可以将对象拷贝到
一个本地缓存并进行直接访问。
对异构系统而言,对象只能由其方法访问这个事实还有一个好处,
即在不同场合使用不同的数据格式,使用RMI访问对象方法的客户
不会注意到数据格式的不同
56
4.4.1 RMI的设计问题
分布式对象模型
◦ 每个进程包含若干对象,其中有些对象既可以接收远程调用,又可以接
收本地调用,而其他对象只能接收本地调用
local
remote
invocation
A
B
C
local E
invocation
invocation
local
invocation
D
remote
invocation
F
Figure 5.12 Remote and local method invocations
57
4.4.1 RMI的设计问题
远程对象:是指能够接收远程调用的对象
◦ 图5-12中,B和F是远程对对象
远程对象引用:如果对象能够访问远程对象的远程对象引用,那么
它们就可以被远程调用。
◦ 图5-12中,B的远程对象引用必须对A是可用的
远程接口:每个远程对象都一个远程接口,由该接口指定哪些方法
可以被远程调用
◦ 图5-12中,对象B和F必须具有远程接口
58
4.4.1 RMI的设计问题
远程对象引用
◦ 用于整个分布式系统的标识符,它指向某一个唯一的远程对象
◦ 它的表示通常与本地对象引用不同
◦ 远程对象引用与本地对象引用在以下方面类似:
◦ 调用者通过远程对象引用指定接收远程方法调用远程对象
◦ 远程对象引用可以作为远程方法调用的参数和结果传递
59
4.4.1 RMI的设计问题
远程接口
◦ 远程对象的类实现其远程接口中的方法
◦ 例如:在Java中作为公有实例方法实现
◦ 其他进程中的对象只能调用属于其远程接口的方法
◦ 注意:和所有接口一样,远程接口没有构造函数
remoteobject
remote
interface
{
Data
m1
m2
m3
implementation
of methods
m4
m5
m6
Figure 5.13 A remote object and its remote interface
60
4.4.1 RMI的设计问题
远程接口
◦ CORBA系统定义了一种接口定义语言IDL,用于定义远程接口
◦ 远程对象的类和客户程序可以用任何IDL编译器适用的语言实现
◦ CORBA客户不需要为了远程调用其方法而使用与远程对象相同的语言
◦ Java RMI中,远程接口以和任何其他Java接口相同的方式定义。
◦ 它们通过扩展名为Remote的接口而获得远程接口的能力。
◦ CORBA IDL 和 Java RMI都支持接口的多重继承,即一个接口可以扩展为
一个或多个其他接口
61
4.4.1 RMI的设计问题
分布式对象系统中的动作
◦ 一个动作是由方法调用启动的,这可能会导致其他对象上的方法调用
◦ 但是在分布式情形下,涉及一连串相关调用的对象可能处于不同的进程
或不同的计算中
◦ 当调用跨越了进程或计算机的边界时,就要使用RMI,此时,对象的远
程引用必须对调用者是可用的
62
4.4.1 RMI的设计问题
分布式对象系统中的动作
◦ 当一个动作导致一个新的对象被实例化时,这个对象的生命周期通常就
是实例化该对象的进程的生命周期
◦ 分布式应用可以提供一些远程对象,通过这些对象提供的方法,可以实
例化另一些对象,而这些新实例化的对象可以通过RMI来访问。
Figure 5.14 Instantiation of remote objects
63
4.4.1 RMI的设计问题
分布式对象系统中的无用单元收集
◦ 如果一个语言支持无用单元收集,那么任何与之相关的RMI系统也应该
支持远程对象的无用单元收集。
◦ 分布式无用单元收集通常通过已有的本地无用单元收集器和一个执行分
布式无用单元收集的附加模块的协作来实现。
异常
◦ 任何远程调用都可能会因为被调用的对象的种种原因而失败
◦ 远程调用方法应该能够引起异常
◦ CORBA IDL提供了指定应用级异常表示法。CORBA客户程序要能处理异常。
64
4.4.2 RMI的实现
完成远程方法调用涉及几个独立的对象和模块
Figure 5.15 The role of proxy and skeleton in remote method invocation
65
4.4.2 RMI的实现
通信模块
◦ 两个相互协作的通信模块执行请求—应答协议
◦ 在客户和服务器之间传递请求和应答消息
◦ 通信模块只使用前三项
◦ 两个通信模块一起负责提供一个指定的调用语义
◦ 服务器端通信模块为被调用的对象类选择分发器,传输其本地引用,该
本地引用取自远程引用模块,用来替换请求消息中远程对象标识符
Figure 5.4 Request-reply message structure
66
4.4.2 RMI的实现
远程引用模块
◦ 远程引用模块负责在本地对象引用和远程对象引用之间进行翻译,并负
责创建远程对象引用
◦ 每个进程中的远程引用模块都有一个远程对象表,该表记录着该进程的
本地对象引用和远程对象引用(整个系统范围内)的对应关系,包括:
◦ 该进程拥有的所有远程对象
◦ 每个本地代理
◦ 远程引用模块的动作:
◦ 当远程对象第一次作为参数或结果传递时,
远程引用模块创建一个远程对象引用,并把它添加表中
◦ 当远程对象引用随代理或应答消息到达时,远程引用模块要提供对应的本地对象引用,它
可能指向一个代理,也可能指向一个远程对象。若远程对象不在表中,则创建一个新的代
理,并将它添加到表中。
67
4.4.2 RMI的实现
伺服器
◦ 提供远程对象主体的类的实例
◦ 由相应的骨架传送的远程请求最终是由伺服器处理
◦ 骨架:远程对象类中有一个骨架,用于实现远程接口中的方法。一个骨架将请求消息中的
参数解码,并调用伺服器等待调用完成。之后将结果和异常信息编码,组成应答消息。
◦ 当远程对象被实例化时,就会生成一个伺服器。
◦ 伺服器的生命周期与远程对象相同,最终也会做为无用单元被回收
68
4.4.2 RMI的实现
RMI软件
◦ 它位于应用层对象和通信模块、远程引用模块之间的软件层组成。
◦ 主要包含如下几种角色:
◦ 代理
◦ 对调用者表现得像调用本地一样,使远程方法调用对客户透明
◦ 不执行调用,而是将调用放在消息里传递给远程对象
◦ 隐藏了远程对象引用的细节、参数的编码、结果的解码以及客户消息的发送和接收
◦ 分发器
◦ 分发器接收来自通信模块的请求消息,并传递请求消息,使用methodId选择骨架中恰当
的方法。分发器和代理对远程接口中的方法使用相同的methodId
◦ 骨架
◦ 远程对象类中有一个骨架,用于实现远程接口中的方法。一个骨架将请求消息中的参数
解码,并调用伺服器等待调用完成。之后将结果和异常信息编码,组成应答消息。
69
4.4.2 RMI的实现
创建代理类、分发器类和骨架类
◦ 在RMI中使用的代理类、分发器类和骨架类由接口编译器自动创建
◦ 例如,在CORBA的Orbix实现中,远程对象接口以CORBA IDL定义,接口编译器能用C++或
JAVA语言创建代理类、分发器类和骨架类。
◦ 对于Java RMI,由远程对象提供的方法集合被定义为一个Java接口,它是在远程对象类中
实现的。Java RMI编译器根据远程对象类创建代理类、分发器类和骨架类。
◦ 动态调用:可替换代理的选择
◦ 上面提到的创建方法是静态的
◦ 客户应用程序可以通过动态调用获得远程调用的一般性表示
◦ 如果应用程序中的某些远程对象的接口不能在设计时确定,那么动态调用接口就会非常有
用
70
4.4.2 RMI的实现
创建代理类、分发器类和骨架类
◦ 动态骨架
◦ 服务器有时需要驻留那些接口在编译时尚不能确定的远程对象
◦ 使用动态骨架可以解决这个问题
◦ 利用一个普通的分发器,将类动态地下载到服务器
71
4.4.2 RMI的实现
服务器和客户程序
◦ 服务器程序包括:分发器类和骨架类,以及它支持的所有伺服器类的实
现,以及初始化部分
◦ 初始化部分负责创建并初始化一个驻留在服务器上的伺服器,其余的伺服器可以应客户发
出的请求和创建
◦ 初始化部分也可以用一个绑定程序注册它的伺服器
◦ 客户程序包含它将调用的所有远程对象的代理类,它用一个绑定程序查
找远程对象引用
◦ 任何远程对象,要想应客户的需求而创建新的远程对象,就必须在它的远程接口中提供用
于此用途的方法。这样的方法称为工厂方法。
72
4.4.2 RMI的实现
绑定程序
◦ 绑定程序是分布式系统中一个单独的服务,它维护一张表,表中包含从
文本名字到远程对象引用的映射
◦ 服务器用该表来按名字注册远程对象,客户用它来查找这些远程对象
◦ Java绑定程序,即RMIregistry
73
4.4.2 RMI的实现
服务器线程
◦ 一旦对象执行远程调用,该调用可能会涉及调用其他远程对象的方法,
因此可能需要过一段时间才会返回
◦ 为了避免一个远程调用的执行延误另一个调用的执行,服务器一般为每
个远程调用的执行分配一个独立的线程
◦ 远程对象实现的设计者必须考虑到并发执行状态的影响
74
4.4.2 RMI的实现
远程对象的激活
◦ 有些应用要求信息能长时间的保留,然而,让表示这一信息的对象无限
期地保留在运行的进程中是不切实际的,并不是所有时间都要使用它们。
◦ 服务器应该在客户需要它们的时候启动
◦ 例如:Inetd服务会根据需要启动FTP
◦ 启动用于驻留远程对象的服务器的进程被称为激活器
◦ 一个远程对象在一个运行的进程中可供调用时,就认为它是主动的
◦ 如果它现在不是主动的,但是可以激活为主动的,就认为它是被动的
◦ 激活是指根据相应的被动对象创建一个主动对象
◦ 具体方法是创建被动对象类的一个新实例,并根据存储的状态初始化它的实例变量
◦ 被动对象可以根据要求被激活
75
4.4.2 RMI的实现
远程对象的激活
◦ 激活器负责
◦ 注册可以被激活的被动对象
◦ 启动已命名的服务器进程并激活进程中的远程对象
◦ 跟踪已经激活的远程对象所在的服务器位置
◦ Java具有将一些远程对象变为可激活的能力
◦ 如果一个可激活的对象被调用时,这个对象的当前状态不是激活状态,那么这个对象将从
它的编码状态转化为激活状态,然后执行调用。
◦ CORBA实例研究中描述了它的实现仓库----一种弱形式的激活器
76
4.4.2 RMI的实现
持久对象存储
◦ 在进程两次激活之间仍然保证存活的对象称为持久对象
◦ 持久对象一般由持久对象存储来管理
◦ 它在磁盘上以编码格式存储持久对象状态,如CORBA持久状态服务、Java Data Object等
◦ 持久对象存储将管理海量的持久对象
◦ 这些持久对象都存储在磁盘或数据库中,直到需要它们的时候才被调用
◦ 当这些持久对象的方法被其他对象调用的时候,它们才能被激活
◦ 激活一般都设计为透明的
◦ 调用者应该不能判断一个对象是已经存在主存中,还是在其方法被调用之前已经激活
◦ 主存中不再需要的持久对象要变成被动的
77
4.4.2 RMI的实现
持久对象存储
◦ 对象只要到达一个一致的状态,就能够保存在持久对象存储中
◦ 持久对象存储需要一个决定何时钝化对象的策略
◦ 持久对象存储一般要对钝化进行优化,即只保存那些上次保存以来修改过的对象
◦ 持久对象存储一般允许相关持久对象集具有可读的名字
◦ 例如:路径名或URL
◦ 两种方法可以判断一个对象是否是持久的
◦ 持久对象存储维护一些持久根,任何可以通过持久跟访问到的对象都被定义为持久的
◦ 持久对象存储提供一些持久类---持久对象属于它们的子类
◦ 有些持久对象存储,允许对象在用户的多个本地缓存中激活,而不是在
服务器中激活。这种情况下,就要求有缓存一致性协议。
78
4.4.2 RMI的实现
对象定位
◦ 有些远程对象在其整个生命周期里,会存在于一系列不同的进程中,可
能这些进程存在于不同的计算机中。
◦ 这种情况下,远程对象引用不能当做地址来用
◦ 发送调用的客户同时需要一个远程对象引用和一个调用发送到的地址
◦ 定位服务帮助客户根据远程对象引用定位远程对象
◦ 使用一个数据库,该数据库用于将远程对象引用映射到它们当前的大概位置
◦ 位置是大概的,因为对象可能已经从已知的前一次位置前移了
◦ 例如:Clouds系统和Emerald系统使用缓存/广播方案
◦ 每个计算机上的定位服务ide一个成员拥有一个小缓存,存放远程对象引用-位置映射
◦ 如果远程对象引用位于缓存中,就尝试调用这个地址
◦ 如果对象已经移动了,调用会失败
◦ 为了定位一个已经移动的对象或者位置不在缓存中的对象,系统需要广播一条请求
79
4.4.3 分布式无用单元收集
分布式无用单元收集器的目的是提供如下保证:
◦ 如果一个本地对象引用或者远程对象引用还在分布式对象集合中任何地
方,那么该对象本身将继续存在,但是没有任何对象引用它时,该对象
将被收集,并且它使用的内存将被回收。
◦ Java分布式无用单元收集算法主要是是基于引用计数
◦ 一旦一个远程对象引用进入一个进程,进程就会创建一个代理,主要需要这个代理,它就
会一直存在。
◦ 对象所在的进程应该告知给客户上的新代理
◦ 随后当客户不再有代理时,也应该告知服务器
80
4.4.3 分布式无用单元收集
分布式无用单元收集器与本地无用单元收集器按如下方式协作:
◦ 每个服务器进程为它的每个远程对象维护拥有远程对象引用的一组进程名
◦ 例如: B.holders是具有对象B的代理的客户进程的集合。这个集合可以放在远程对象表的
一个附加列里
◦ 当客户C第一次接收到远程对象B的远程引用时,它发送一个addRef(B)调用到远程对象的服
务器并创建一个代理,服务器C添加到B.holders
◦ 当客户C的无用单元收集器注意到远程对象B的一个代理不再可达时,它发送一个
removeRef(B)调用到相应的服务器,然后删除该代理,服务器从B.holders中删除C
◦ 如果不存在B的一些本地持有者,当B.holders为空时,服务器的本地无用单元收集器将回
收被B占用的空间
81
4.4.3 分布式无用单元收集
通过在进程和远程引用模块之间采用至多一次调用语义的请求—应
答通信可实现该算法。它不要求任何全局同步。
但要注意,为无用单元收集算法所发送的额外调用不能影响到每个
正常的RMI,它们只在代理创建和删除的时候发生。
有一种可能,一个客户发出一个removeRef(B)调用的同时,另一个
客户恰好发送addRef(B)调用。如果removeRef(B)调用先到达而此时
B.holders为空,那么远程对象B可能会在addRef(B)调用来到之前被
删除。
82
4.4.3 分布式无用单元收集
Java 分布式无用单元收集通过使用下面方法来容忍通信故障
◦ addRef和removeRef为幂等操作
◦ 当addRef(B)调用返回一个异常时,客户不创建代理还是发送一个
removeRef(B)调用。removeRef的效果是否正确取决于addRef是否成功。
removeRef失败的情况通过租借来处理。
Java分布式无用单元收集算法可以容忍客户进程故障
◦ 服务器将它们的对象租借给客户一段有限时间
◦ 租借期从客户给服务器发出addRef调用开始,到达过期时间或者客户给
服务器发出一个removeRef调用后终止
◦ 存储在服务器端关于每个租借的信息包括客户虚拟机的标识符和租期
◦ 客户负责在租期过期之前向服务器请求续借
83
4.4.3 分布式无用单元收集
Jini中的租借
◦ Jini分布式系统包括一个租借规约,它可以用于一个对象给另一个对象提
供一种资源的各种情形,例如远程对象提供远程对象引用给其他对象。
◦ 提供这种资源的对象要冒一些风险,即在用户不再对其感兴趣或者它们
的程序可能已经退出的情况下,对象还不得不维护该资源。
◦ 为了避免用复杂的协议判断资源对用户是否还有兴趣,资源只提供一段
有限的时间。允许一段时间内使用资源的授权称为租借。提供资源的对
象会负责维护它直到租期结束。资源的用户负责在过期的时候请求延续
它们的租约。
Java RMI中,表示租借的对象实现Lease接口,该接口包含关于租期
的信息和能令租借延续或取消的方法。
84
4.5 实例研究:Java RMI
Java RMI扩展了Java的对象模型,以便为Java语言中的分布式对象提
供支持
它允许对象用与本地调用相同的语法调用远程对象上的方法。而且
类型检查也等效地应用到本地调用和远程调用
发出远程调用的对象知道它的目标对象是远程的,因为它必须处理
RemoteException;并且远程对象的实现者也知道它是远程的,因为
它必须实现Remote接口
由于调用者和目标对象彼此是远程的,因此其参数传递语义是不同
的
85
4.5 实例研究:Java RMI
用Java RMI进行分布式应用的编写相对来说较为容易,因为它是一
个单语言系统---远程接口用Java语言实现。
如果使用一个多语言系统(如CORBA),程序员需要学习IDL,并理
解它如何映像到实现语言中。
不过,即使在一个单语言系统中,远程对象的程序员也必须考虑它
在并发环境下的行为
86
4.5 实例研究:Java RMI
共享白板
◦ 设计要求
◦ 允许一组用户共享一个绘图区域的分布式程序
◦ 该绘图区域可以包含图形对象:矩形、线、圆等
◦ 每个图形由一个用户绘制
◦ 服务器功能
◦ 为客户提供操作,用于把用户最新绘制的图形告诉服务器,并记录它接收到的所有图形。
◦ 让客户通过轮询服务器的方式获取由其他用户绘制的最新图形。
◦ 每当新图形到达的时候,版本号就递增,并赋予给该新图形。
◦ 让客户询问它的版本号和每个图形的版本号,以避免客户取得它们已经有的图形。
87
4.5 实例研究:Java RMI
Java RMI中的远程接口
◦ 远程接口通过扩展Java.rmi包中的Remote接口来定义
◦ 方法必须抛出RemoteException异常,但是也可以抛出特定于应用的异常
import java.rmi.*;
import java.util.Vector;
public interface Shape extends Remote {
int getVersion() throws RemoteException;
GraphicalObject getAllState() throws RemoteException;
1
}
public interface ShapeList extends Remote {
Shape newShape(GraphicalObject g) throws RemoteException;
Vector allShapes() throws RemoteException;
int getVersion() throws RemoteException;
}
2
Figure 5.16 Java Remote interfaces Shape and ShapeList
88
4.5 实例研究:Java RMI
传递参数和结果
◦ Java RMI中假定方法的参数为输入型参数,而方法的结果为输出型参数
◦ 任何可序列化的对象都能作为Java RMI中的参数和结果传递
◦ 所有的简单类型和远程对象都是可序列化的
◦ 在必要的时候,作为参数和结果值的类可以由RMI系统下载给接收者
◦ 传递远程对象
◦ 当将参数或者结果值类型定义为远程接口的时候,相应的参数或者结果总是作为远程对象
引用传递
◦ 传递非远程对象
◦ 所有可序列化的非远程 对象是在复制之后以值方式传递
◦ 当一个对象以值传递时,就要在接收者的进程中创建一个新的对象。这个新对象的方法可
以在本地调用,但这可能导致它的状态与发送者进程中原来的对象状体不同
89
4.5 实例研究:Java RMI
传递参数和结果
◦ 远程调用中的参数和返回值用3.3.2节描述的方法被序列化到一个流中,
并做一下改变:
◦ 一旦一个实现Remote接口的对象被序列化,它就被它的远程对象引用代替,该远程对象引
用包含它类的名字
◦ 任何一个对象被序列化的时候,它的类信息就加注了该类的地址(作为一个URL),使该
类能由接收者下载
90
4.5 实例研究:Java RMI
类的下载
◦ Java允许类从一个虚拟机下载到另一个虚拟机,这与以远程调用方式通信的分布
式对象尤其相关。
◦ 非远程对象以值方式传递,而远程对象以引用方式传递RMI参数和结果
◦ 如果接收者还没有拥有以值方式传递的对象类,那么它会自动下载类的代码
◦ 如果远程对象引用的接收者还没有拥有代理类,那么代理类的代码也会自动下载
◦ 这种方式的优势:
◦ 不必为每个用户在他们的工作环境中保留相同的类集合
◦ 一但添加了新类,客户和服务器程序能透明地使用它们的实例
91
4.5 实例研究:Java RMI
RMIregistry
◦ JAVA RMI的绑定程序
◦ RMIregistry的一个实例必须运行在每个驻留了远程对象的服务器计算机
◦ 它维护着一张表,将文本格式的URL风格的名字映像到驻留在该计算机
上的远程对象引用
◦ 它通过Naming类的方法来存取,Naming类的方法以一个URL格式的字符
串作为参数
◦ //computeName:port/objectName
◦ 其中computeName和port指向RMIregistry地址,如果它们被省略,就被认为是本地计算机
默认端口
92
4.5 实例研究:Java RMI
RMIregistry
void rebind (String name, Remote obj)
This method is used by a server to register the identifier of a remote object by
name, as shown in Figure 15.18, line 3.
void bind (String name, Remote obj)
This method can alternatively be used by a server to register a remote object by
name, but if the name is already bound to a remote object reference an
exception is thrown.
void unbind (String name, Remote obj)
This method removes a binding.
Remote lookup(String name)
This method is used by clients to look up a remote object by name, as shown in
Figure 5.20 line 1. A remote object reference is returned.
String [] list()
This method returns an array of Strings containing the names bound in the registry.
Figure 5.17 The Naming class of Java RMIregistry
93
4.5.1 创建客户和服务器程序
白板服务器程序
◦ 把每种图形表示成一个实现Shape接口的伺服器
◦ 拥有图形对象的状态和版本号
◦ 实现ShapeList接口的伺服器代表它的图形集,并把图形集放在Vector中
◦ 服务器包含一个main方法和一个伺服器类(Servant)
94
Figure 5.18
Java class ShapeListServer with main method
import java.rmi.*;
public class ShapeListServer{
public static void main(String args[]){
System.setSecurityManager(new RMISecurityManager());
try{
ShapeList aShapeList = new ShapeListServant();
Naming.rebind("Shape List", aShapeList );
System.out.println("ShapeList server ready");
}catch(Exception e) {
System.out.println("ShapeList server main " + e.getMessage());}
}
}
1
2
Instructor’s Guide for Coulouris, Dollimore, Kindberg and Blair, Distributed Systems: Concepts and Design Edn. 5
© Pearson Education 2012
95
Figure 5.19
Java class ShapeListServant implements interface ShapeList
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.util.Vector;
public class ShapeListServant extends UnicastRemoteObject implements ShapeList {
private Vector theList; // contains the list of Shapes
private int version;
public ShapeListServant()throws RemoteException{...}
public Shape newShape(GraphicalObject g) throws RemoteException { 1
version++;
Shape s = new ShapeServant( g, version);
2
theList.addElement(s);
return s;
}
public Vector allShapes()throws RemoteException{...}
public int getVersion() throws RemoteException { ... }
}
Instructor’s Guide for Coulouris, Dollimore, Kindberg and Blair, Distributed Systems: Concepts and Design Edn. 5
© Pearson Education 2012
96
4.5.1 创建客户和服务器程序
白板客户程序
import java.rmi.*;
import java.rmi.server.*;
import java.util.Vector;
public class ShapeListClient{
public static void main(String args[]){
System.setSecurityManager(new RMISecurityManager());
ShapeList aShapeList = null;
try{
aShapeList = (ShapeList) Naming.lookup("//bruno.ShapeList")
Vector sList = aShapeList.allShapes();
} catch(RemoteException e) {System.out.println(e.getMessage());
}catch(Exception e) {System.out.println("Client: " + e.getMessage());}
}
}
;
1
2
Figure 5.20 Java client of ShapeList
97
4.5.1 创建客户和服务器程序
回调
◦ 基本思想是,客户不用为找出某个事件是否已经发生而轮询服务器,而
是当事件发生时,由服务器通知它的客户。回调是指服务器为某一事件
通知客户的动作。
◦ 在RMI中按如下方式实现回调:
◦ 客户创建一个远程对象,该对象实现一个接口,接口中包含一个供服务器调用的方法。
◦ 服务器提供一个操作,让感兴趣的客户通知服务器客户的回调对象的远程对象引用,服务
器将这些引用记录在一张列表中。
◦ 一旦感兴趣的事件发生,服务器就调用感兴趣的客户
◦ 使用回调可以避免客户轮询服务器上的兴趣对象所造成的缺点:
◦ 服务器的性能会因为时常的轮询而降低
◦ 客户不能及时知道已经做了更新
98
4.5.1 创建客户和服务器程序
回调
◦ 回调的问题
◦ 服务器需要有客户回调对象的最新列表
◦ 服务器需要发送一系列同步的RMI给列表中的回调对象
public interface WhiteboardCallback implements Remote{
void callback(int version) throws RemoteExcetpion
};
由客户将该接口作为远程对象实现,并通知服务器它的回调对象
99
4.5.2 Java RMI的设计实现
最初的Java RMI系统实现了右图中所有类
Java 1.2 之后使用反射机制来创建通用
分发器并避免骨架的使用
反射的使用
◦ 反射用于传递请求消息中关于被调用方法的信息
◦ 借助反射包中的Method类完成
◦ Method的每个实例代表一个方法的特征,包括:
◦ 类、参数类型、返回值和异常
◦ Method的实例能够通过它的invoke方法被一个合适的类的对象调用
◦ Invoke方法需要两个参数:指定接收调用的对象和包含参数的Object数
组。结果也作为Object类型返回。
100
4.5.2 Java RMI的设计实现
支持RMI的Java类
Figure 5.21 Classes supporting Java RMI
101
Question?
102