中间件实验2 远程方法调用RMI的设计与部署

1.实验目的和要求

客户端程序调用服务器端的远程对象的一个方法,实现两个整数的相加,将相加的和返回给客户端并显示。

2. 实验原理

服务器端提供服务,服务中要暴露可以调用的远程方法,以接口的形式表现,这样在客户端可以通过服务接口来调用远程方法,实现复杂的业务逻辑。在服务器端,首先要对接口中提供的方法实现,,完成了客户请求的调用的过程,将获取到的调用方法的结果通过序列化机制返回给客户端,进行应答。在客户端,通过Stub来接收服务器返回的数据(对象),即在这里进行了反序列化,也就是读取网络传输的字节流,进而进行重构。

3.实验过程

分为以下几个步骤:

1. 创建远程接口及声明远程方法(AddInterface.java)

2. 实现远程接口及远程方法(继承UnicastRemoteObject)(RMIAddImpl.java)

3. 启动RMI注册服务,并注册远程对象(AddServant.java)

4. 客户端查找远程对象,并调用远程方法(AddClient)

5. 执行程序:开启3个控制台窗口,一个运行rmiregistry,一个运行服务器,一个运行客户端

 

1. 创建远程接口及声明远程方法(AddInterface.java)

import java.rmi.*;
/* 远程接口仅仅是一个接口,RMI客户机可以直接使用它,RMI伺服器必须通过一个远程对象来实现它,并用某个URL注册它的一个实例。远程接口必须是public的,此外,它的每个方法都必须抛出RemoteException。*/
//远程接口
public interface AddInterface extends Remote {
// 返回“返回两数结果为:”
public String Add() throws RemoteException;
// 返回“相加结果”
public float AddToSomeBody(float x,float y)
throws RemoteException;
}
 

2. 实现远程接口及远程方法(继承UnicastRemoteObject)(RMIAddImpl.java)

import java.rmi.*;
import java.rmi.server.*;

/* 远程接口的实现类真正实现RMI客户调用的远程对象,它必须从UnicastRemoteObject继承,其构造方法应抛出RemoteException异常。*/

//远程接口的实现
public class RMIAddImpl extends UnicastRemoteObject implements AddInterface {
public RMIAddImpl() throws RemoteException {
}

// 返回"两数相加结果为:"
public String Add() throws RemoteException {
return "两数相加结果为:";
}
// 返回“返回结果!”
public float AddToSomeBody(float x,float y)
throws RemoteException {
return x+y;
}
}


3. 启动RMI注册服务,并注册远程对象(AddServant.java)

import java.rmi.*;
import java.rmi.registry.*;
import java.net.*;
/* 该类创建远程对象实现RemImpl的一个实例,然后用一个特定的URL 来注册它。册,就是通过Naming.bind或Naming.rebind来将RemImpl实例绑定到URL上。*/
//RMI服务器程序
public class AddServant {
public static void main(String[] args) {
try {
 //创建一个远程对象
RMIAddImpl rAdd = new RMIAddImpl();
Naming.rebind("rmi://localhost:8888/RAdd", rAdd);
System.out.println("INFO 远程对象RHello绑定成功!");
} catch (RemoteException e) {
System.out.println("创建远程对象发生异常!");
e.printStackTrace();
} catch (MalformedURLException e) {
System.out.println("发生URL畸形异常!");
e.printStackTrace();
}
}
}

4. 客户端查找远程对象,并调用远程方法(AddClient)

import java.net.MalformedURLException;
import java.nio.charset.MalformedInputException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.Scanner;

//RMI客户端程序
public class AddClient {
public static void main(String[] args) {
try {
// 在RMI服务注册表中查找名为RHello的对象,并调用其上的方法
       	Scanner scanner = new Scanner(System.in);
	System.out.println("请输入服务器ip");
	String ip =scanner.nextLine();
AddInterface radd = (AddInterface) Naming
.lookup("rmi://"+ ip + ":8888/RAdd");

	System.out.println("请输入两个整数");
	int x=scanner.nextInt();
	int y=scanner.nextInt();
System.out.println(radd.Add());
System.out.println(radd.AddToSomeBody(x,y));
} catch (NotBoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}

5.执行程序:开启3个控制台窗口,一个运行rmiregistry,一个运行服务器,一个运行客户端

编译四段代码并生成class文件,分别新建两个文件夹命名为AddServer和AddClient,将AddInterface、RMIAddImpl和AddServant的class文件放在AddServet文件夹中,将AddInterface,AddClient的class文件放在AddClient文件夹中。之后进入AddServant使用RMI编译器编译具体实现类RMIAddImpl生成RMIAddImpl.class.Stub文件,将RMIAddImpl.class.Stub放在AddServer文件夹和AddClient文件夹中各一个.

 

运行rmiregistry


运行服务器

 

运行客户端

4.实验小结

(1)Stub和Skeleton在什么位置产生

从JDK5.0以后,这两个类就不需要rmic来产生了,而是有JVM自动处理,实际上他们还是存在的。Stub存在于客户端,作为客户端的代理,让我们总是认为客户端产生了stub,接口没有作用。实际上stub类是通过java动态类下载的,字是由服务端道理,然后根据南需要动态的加截到客户端,如果下次再运行这个客户端该存根类存在于classpath中,它就不需要再下载了,而是直接加载。总的来说,stub是在服务端产生的,如果服务端的stub内容改变,那么客户端的也是需要同步更新。

(2)Stub和公共接口interface(远程对象的功能)的关系

一个服务如果没有合适的存根类,客户就没有办法去调用远程的接口,RMI使用存根来返回引用远程对象接口的参数。在类的关系中,接口不有实例化的,但是它可以指向一个实现该接口的实例。存根和接口就是这种关系,而存根类的实例就是在:lookup()方法调用时加载、实例的。接口只是告诉JVM,内存中这片的字节码中,这几个方法我可以调用。

(3)rmiregistry

Rmiregistry需要在提供远程对象服务端启动,它提供了一个环境,就是在内存中,开辟了一片空间,用来接受服务端服务程序的注册,产生一个类似于数据库,提供存储检索远程对象功能的注册表。这个RMI注册表,就是我们常听到的RMI名字服务。远程客户端,就是依告它获得存根,调用远程主法。这里有一个端口的问题,如果你在启动rmiregistry时,设定了非默认端口,那么需要在服务端在客户端统一使用端口,否则就会有RemoteException的异常抛出,rmiregidstry提供的服务是针对特定的端口号的,不然在同一台机器上也是无法提供服务。

 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值