javaRMI及简单实例

更新时间:2024-03-14 00:50:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

远程方法调用实验报告

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 e=namingContext.list(\while(e.hasMore())

System.out.println(e.next().getName());

(5)运行RMI应用

假定实验程序编译后的类文件都位于F:\\MyWorkspace\\workspace\\javaRMI\\bin目录下:

在DOS下转到F:\\MyWorkspace\\workspace\\javaRMI\\bin目录下,先后运行以下命令:

1)使用rmic对RemoteServiceClass.class进行编译,生成代理类RemoteServiceClass_Stub.class,如下:

2)启动rmi注册表,如下:

3)启动服务器端程序,如下:

4)启动客户端程序,如下:

5.实验结果及分析

1、程序运行结果

RemoteServer端的打印结果如下:

RemoteClient端的打印结果如下:

2、结果分析

服务器端的打印结果看,在服务器注册了两个RemoteServiceClass对象,分别为“RemoteService1”和

“RemoteService2”。并且客户端程序分别调用了这两个远程对象的echo()和getDate()方法。而且客户端得到的仅仅是echo()和getDate()方法的返回结果。

在客户端,执行以下代码时:

HelloService

service1=(HelloService)namingContext.lookup(url+\Class stubClass=service1.getClass();

System.out.println(\是\的实例\ Class[] interfaces=stubClass.getInterfaces(); for(int i=0;i

System.out.println(\存根类实现了\

客户端的打印结果为:

由此可见,Context对象lookup()方法返回的是一个名为“RemoteServiceClass_Stub”的代理类的实例,它实现了RemoteService远程接口,这个代理类的实例就是客户程序所访问的RemoteServiceClass远程对象的存根对象。

在客户端,执行以下代码时:

System.out.println(service1.echo(\ System.out.println(service1.getTime()); System.out.println(service2.echo(\ System.out.println(service2.getTime());

客户端的打印结果为:

由此可见,当客户端通过存根调用服务器端的RemoteServiceClass对象的echo()和getDate()方法时,在服务器

端执行对象的echo()和getDate()方法,因此echo()和getDate()方法的第一行语句打印在服务器端输出打印结果,而不会在客户端输出打印结果。客户端得到的仅仅是echo()和getDate()方法的返回结果。

6.小结

通过此次实验,对java中远程方法调用(RMI)框架的基本原理和应用方法有了较好的理解与学习,了解了java中创建一个RMI应用的基本步骤,对RMI有了更深刻的认识。通过对此实验的实现,动手能力也有了一定的提高。

完成此次实验,受益颇丰。

7.参考文献

[1] 孙卫琴.java网络编程精解[M].北京:电子工业出版社,2007

8.附录

(1)远程接口(RemoteService.java):

package hello;

import java.util.Date; import java.rmi.*;

public interface RemoteService extends Remote{

public String echo(String msg) throws RemoteException; public Date getTime() throws RemoteException; }

(2)远程类(RemoteServiceClass.java):

package hello;

import java.util.Date; import java.rmi.*;

import java.rmi.server.UnicastRemoteObject;

public class RemoteServiceClass extends UnicastRemoteObject implements RemoteService{

private String name;

}

public RemoteServiceClass(String name) throws RemoteException { this.name=name; }

public String echo(String msg) throws RemoteException{ System.out.println(name+\:调用echo()方法\ return \:\}

public Date getTime() throws RemoteException{ System.out.println(name+\:调用getTime()方法\ return new Date(); }

(3)服务器程序(RemoteServer.java):

package hello; import java.rmi.*;

import javax.naming.*;

public class RemoteServer {

public static void main(String args[]){ try{ RemoteService service1=new RemoteServiceClass(\ RemoteService service2=new RemoteServiceClass(\ Context namingContext=new InitialContext(); namingContext.rebind(\ namingContext.rebind(\ System.out.println(\服务器注册了两个RemoteServiceClass对象:service1,service2\ }catch(Exception e){ e.printStackTrace(); } } }

(4) 客户程序(SimpleClient.java):

package hello; import java.rmi.*;

import javax.naming.*; public class RemoteClient {

public static void showRemoteObjects(Context namingContext)throws Exception{ NamingEnumeration e=namingContext.list(\ while(e.hasMore()) System.out.println(e.next().getName());

} public static void main( String args[] ){ String url=\ try{

System.setProperty(\cy\ System.setSecurityManager(new RMISecurityManager()); Context namingContext=new InitialContext(); RemoteService

service1=(RemoteService)namingContext.lookup(url+\ RemoteService

service2=(RemoteService)namingContext.lookup(url+\ Class stubClass=service1.getClass(); System.out.println(\是\的实例\ Class[] interfaces=stubClass.getInterfaces(); for(int i=0;i

本文来源:https://www.bwwdw.com/article/glq8.html

Top