欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > RMI介绍

RMI介绍

2025/5/3 3:58:04 来源:https://blog.csdn.net/weixin_68408599/article/details/144613131  浏览:    关键词:RMI介绍

1.1、什么是 RMI

RMI 是 Java 中的一种技术,全称为远程方法调用(Remote Method Invocation)。它的作用是允许你在不同的 Java 虚拟机(JVM)之间进行通信,就像在同一个 JVM 中调用方法一样,调用远程方法。这些虚拟机可以在不同的主机上、也可以在同一个主机上。

RMI 是 Java 的一组拥护开发分布式应用程序的 API。RMI 使用 Java 语言接口定义了远程对象,它集合了 Java 序列化和 Java远程方法协议(Java Remote Method Protocol)。

简单地说,原先的程序仅能在同一操作系统的方法调用,通过 RMI 可以变成在不同操作系统之间对程序中方法的调用。

RMI 依赖的通信协议是 JRMP。JRMP: Java 远程方法协议(Java Remote Method Protocol,JRMP),是特定于 Java 技术的通信协议,主要是用于查找和引用远程对象的协议。

RMI 对象是通过序列化方式进行传输的。

Java RMI 的出现可以是客户端运行的程序调用远程服务器上的方法,对于调用的这个过程,我们只需关注对象方法的本身,而不用在关注网络协议的各种问题。

有这么一段描述,讲述了 RMI 的一种使用场景,便于大家去理解。

https://paper.seebug.org/1012/

假设A公司是某个行业的翘楚,开发了一系列行业上领先的软件。B公司想利用A公司的行业优势进行一些数据上的交换和处理。但A公司不可能把其全部软件都部署到B公司,也不能给B公司全部数据的访问权限。于是A公司在现有的软件结构体系不变的前提下开发了一些RMI方法。B公司调用A公司的RMI方法来实现对A公司数据的访问和操作,而所有数据和权限都在A公司的控制范围内,不用担心B公司窃取其数据或者商业机密。

对于开发者来说,远程方法调用就像我们本地调用一个对象的方法一样,他们很多时候不需要关心内部如何实现,只关心传递相应的参数并获取结果就行了。但是对于攻击者来说,要执行攻击还是需要了解一些细节的。

1.2、RMI 中的三个角色

RMI中涉及到三个角色,它们分别为服务端(Server),注册中心(Registry)和客户端(Client),下面是他们的作用。

服务端(Server):负责将远程对象绑定至注册中心。

注册中心(Registry):服务端会将远程对象绑定至此。客户端会向注册中心查询绑定的远程对象。

客户端(Client):与注册中心和服务端交互。

插入一张来自互联网的图片,直观展示了他们的关系。

存根/桩(Stub):客户端侧的代理,每个远程对象都包含一个代理对象stub,当运行在本地 Java 虚拟机上的程序调用运行在远程 Java 虚拟机上的对象方法时,它首先在本地创建该对象的代理对象 stub, 然后调用代理对象上匹配的方法。

骨架(Skeleton):服务端侧的代理,用于读取 stub 传递的方法参数,调用服务器方的实际对象方法, 并接收方法执行后的返回值。

⚠️注意:在低版本的 JDK 中,Server 与 Registry 是可以不在一台服务器上的,而在高版本的 JDK 中,Server 与 Registry 只能在一台服务器上,否则无法注册成功。比如 Jdk8u121 这个分界线。

1.2.1、存根和骨架

存根和骨架是远程对象实现中的重要组成部分。当您在远程对象上调用方法(可能位于不同的主机上)时,实际上是在调用一些本地代码,它充当该对象的代理。这就是存根。(称其为存根是因为它类似于对象的截断占位符。)而骨架则是另一个代理,它与真实对象一起存在于其原始主机上。它接收来自存根的远程方法调用,并将其传递给对象。

创建存根和骨架后,您无需直接操作它们;它们对您是隐藏的(可以说是藏在壁橱里)。您可以通过运行rmic(RMI编译器)实用程序来为您的远程对象创建存根和骨架。在通常编译Java源文件后,作为第二步,您需要对远程对象类运行rmic。这一过程非常简单;我们将在下面的示例中向您展示具体操作方法。

Remote Method Invocation (RMI) - Learning Java [Book]

1.3、示例代码1

老规矩,先创建一个名为rmidemo的工程文件。并在java目录下创建三个包,分别名为method,rmiclient,rmiserver。最终目录结构如下图所示:

RMI 代码编写步骤如下:

  1. 创建远程接口及声明远程方法(SayHello.java)
  2. 实现远程接口及远程方法(继承UnicastRemoteObject)(SayHelloImpl.java)
  3. 启动 RMI 注册服务,并注册远程对象(RmiServer.java)
  4. 客户端查找远程对象,并调用远程方法(RmiClient.java)
  5. 执行程序:启动服务端RmiServer;运行客户端RmiClient进行调用

我们对上面流程进行拆解,编写对应的代码。

①、创建远程接口及声明远程方法

一定要先创建声明一个远程方法,才能用于后续的远程方法调用。在这里我们以经典的Hello World为例。远程方法中的接口均要继承Remote,实际上Remote类中没有任何代码,继承也仅是为了说明该是接口使用于远程方法。

在src.main.java.method目录下新建一个名为SayHello的Java Interface,并键入以下代码,最终如下图所示:

package method;
import java.rmi.Remote;
import java.rmi.RemoteException;public interface SayHello extends Remote {public String sayhello(String name) throws RemoteException;
}
②、实现远程接口及远程方法

此步骤编写远程方法中具体实现代码。需要注意的是,它必须继承UnicastRemoteObject类,表明其可以作为远程对象,并可以被注册到注册中心,最终可以让客户端远程调用。

在src.main.java.method目录下新建一个名为SayHelloImpl的Java Class,并键入以下代码,最终如下图所示:

package method;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;public class SayHelloImpl extends UnicastRemoteObject implements SayHello{public SayHelloImpl() throws RemoteException {super();}@Overridepublic String sayhello(String name) throws RemoteException {return "Hello,i am " + name;}
}
③、启动RMI注册服务,并注册远程对象

这个步骤我们是编写RMI服务端代码,需要将上面编写的远程方法注册到注册中心去。

在src.main.java.rmiserver目录下新建一个名为RmiServer的Java Class,并键入以下代码,最终如下图所示:

package rmiserver;import method.SayHello;
import method.SayHelloImpl;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;public class RmiServer {public static void main(String[] args) throws RemoteException {System.out.println("远程方法创建等待调用ing......");//创建远程对象SayHello sayhello = new SayHelloImpl();//创建注册表Registry registry = LocateRegistry.createRegistry(1099);//将远程对象注册到注册表里面,并且取名为sayhelloregistry.rebind("sayhello",sayhello);}
}
④、客户端查找远程对象,并调用远程方法

这个步骤我们是编写RMI客户端代码,主要是获取到注册中心代理,查询具体注册的远程方法并调用。

在src.main.java.rmiclient目录下新建一个名为RmiClient的Java Class,并键入以下代码,最终如下图所示:

package rmiclient;import method.SayHello;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;/*** 编号7089*/
public class RmiClient {public static void main(String[] args) throws RemoteException, NotBoundException {//获取到注册中心的代理Registry registry = LocateRegistry.getRegistry("localhost", 1099);//利用注册中心的代理去查询远程注册表中名为sayhello的对象SayHello sayhello = (SayHello) registry.lookup("sayhello");//调用远程方法System.out.println(sayhello.sayhello("POWER7089"));}
}
⑤、执行程序

这个步骤我们运行程序观察结果。

首先,启动服务端RmiServer,如下图所示:

最后,启动客户端RmiClient,如下图所示:

大家动手调试下吧。

1.4、示例代码2

Calculator 声明远程接口,如下所示:

import java.rmi.Remote;
import java.rmi.RemoteException;public interface Calculator extends Remote {int add(int a, int b) throws RemoteException;
}

Calculator 接口的具体实现方法 - CalculatorImpl,实现了一个基础的加法计算的方法,如下所示:

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;public class CalculatorImpl extends UnicastRemoteObject implements Calculator {public CalculatorImpl() throws RemoteException {super();}public int add(int a, int b) throws RemoteException {return a + b;}
}

RmiServerCalc,RMI 服务器,注册远程对象,如下所示:

import method.Calculator;
import method.CalculatorImpl;import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;public class RmiServerCalc {public static void main(String[] args) {try {// 创建远程对象实例Calculator calculator = new CalculatorImpl();// 将远程对象注册到RMI注册表中Registry registry = LocateRegistry.createRegistry(1099);registry.rebind("CalculatorService", calculator);System.out.println("Calculator 服务已就绪.");} catch (Exception e) {e.printStackTrace();}}
}

RmiClientCalc,客户端访问远程对象,调用相关方法,如下所示:

import method.Calculator;import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;public class RmiClientCalc {public static void main(String[] args) {try {// 查找远程对象Registry registry = LocateRegistry.getRegistry("localhost", 1099);Calculator calculator = (Calculator) registry.lookup("CalculatorService");// 调用远程方法int result = calculator.add(5, 3);System.out.println("5 + 3 = " + result);} catch (Exception e) {e.printStackTrace();}}
}

拓展阅读:

https://paper.seebug.org/1091/
https://y4er.com/posts/java-rmi/
https://goodapple.top/archives/321
https://paper.seebug.org/1251/
https://www.oreilly.com/library/view/learning-java/1565927184/ch11s04.html

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词