远程方法调用实验报告
1.摘要
简单介绍了java中的RMI框架的基本原理及应用,给出了java中创建一个RMI应用的基本步骤。在此基础上设计了一个采用RMI技术实现远程方法调用的实验,客户端调用服务器端的远程对象的方法,获取服务器端的系统时间,将结果返回客户端。此外还对实验结果还进行了分析。
2.实验背景
RMI采用客户/服务器通信方式。在服务器上部署了提供各种服务的远程对象,客户端请求访问服务器上的远程对象的方法。如图1所示,是RemoteServiceClass一个远程对象,它运行在服务器上,客户端请求调用RemoteServiceClass对象的echo()方法。
服务器客户端1.发送参数“hello”对象3.发送返回值“echo.hello”对象远程对象RemoteServiceClass2.调用echo()方法
图1 客户端请求调用服务器上的远程对象的方法 如图2所示,RMI采用代理来负责客户和远程对象之间通过Socket进行通信的细节。RMI框架为远程对象分别生成了客户端代理和服务器端代理。位于客户端的代理类称为存根(Stub),位于服务器端的代理类称为骨架(Skeleton)。
客户端服务器返回值或异常1.发送参数“hello”对象远程对象RemoteServiceClass3.调用echo()方法2.发送被编组的参数远程对象的存根4.发送被编组的返回值或异常远程对象的骨架 图2 RMI框架采用代理来封装通信细节
当客户端调用远程对象的一个方法时,实际上是调用本地存根对象的相应方法。存根对象和远程对象具有同样的接口。存根采用一种与平台无关的编码方式,把方法的参数编码为字节序列,这个编码过程称为参数编组。RMI主要采用java序列化机制进行参数编组。接着,存根把请求信息发送给服务器,服务器端接收到客户端的请求信息,然后由相应的骨架对象来处理这一请求信息,把处理后的返回值或者异常编组后发送给客户。客户端的存根接收到服务器发送过来的编组后的返回值或者异常,再对它进行反编组,就得到调用远程方法的返回结果。
存根与骨架类通过Socket来通信。开发人员无须手工编写客户端的存根类及服务器端的骨架类,它们都由RMI框架创造。在JDK5.0以前的版本中,需要用rmic命令来为远程对象生成静态的代理类(包括存根和骨架类)。而在JDK5.0中,RMI框架会在运行时自动为远程对象生成动态代理类(包括存根和骨架类),从而更彻底封装了RMI框架的实现细节,简化了RMI框架的使用方式。
3.实验环境
使用java语言,平台为MyEclipse。
4.实验方案设计与描述
远程对象所属的类必须实现一个远程接口,由RMI框架负责创建的存根也会实现这个远程接口,在远程接口中声明了可以被客户程序访问的远程方法。实验步骤如下:
(1) 创建远程接口(RemoteService.java):
远程接口中声明了可以被客户程序访问的远程方法。RMI规范要求远程对象所属的类实现一个远程接口,并且远程接口符合以下条件:
1) 直接或者间接继承java.rmi.Remote接口;
2) 接口中的所有方法声明抛出java.rmi.RemoteException. 远程接口RemoteService中声明了echo()和getDate()两个方法,它们都声明抛出RemoteException。 (2) 创建远程类(RemoteServiceClass.java):
远程类就是远程对象所属的类。RMI规范要求远程类必须实现一个远程接口。RemoteServiceClass类就是远程类,它继承了UnicastRemoteObject类,并且实现了RemoteService远程接口。 (3) 创建服务器程序(RemoteServer.java):
服务器程序的一大任务就是向rmiregistry注册表中注册远程对象。以下程序代码注册了一个RemoteServiceClass对象,并且给它命名为“rmi:RemoteService1”:
RemoteService service1=new RemoteServiceClass(\Context namingContext=new InitialContext();
namingContext.rebind(\
服务器程序RemoteServer类的main()方法中,创建了两个RemoteServiceClass对象,然后把它们注册到rmiregistry注册表中,它们的注册名分别为“RemoteService1”和“RemoteService2”。 (4) 创建客户程序(SimpleClient.java):
负责定位远程对象,并且调用远程对象的方法。客户程序SimpleClient类的main()方法中,先获得远程对象的存根对象,然后测试它所属的类,接着调用它的远程方法。
以下程序代码先获得了名为“RemoteService1”的远程对象的存根对象,接着调用存根对象的echo()和getDate()方法:
Context namingContext=new InitialContext();
HelloService
service1=(HelloService)namingContext.lookup(url+\System.out.println(service1.echo(\ System.out.println(service1.getTime());
以下程序代码列举出所有在rmiregistry注册表上注册的远程对象;
NamingEnumeration
System.out.println(e.next().getName());
(5)运行RMI应用
假定实验程序编译后的类文件都位于F:\\MyWorkspace\\workspace\\javaRMI\\bin目录下:
相关推荐: