首先搞明白如下问题:
RMI存在的意义?
RMI技术方面实现?
- RMIServer: 远程服务器,需要实现具体的Java方法并提供接口
RMIServer一般又包括下面这两个部分:
- 方法的实现: 真正意义上的”RMIServer”, 提供远程的对象实现.
- 方法的注册: RMI Registry,注册中心, 需要标记远程对象的位置.
- RMIClient: 本地客户端,需要提供接口的定义
代码的实现?
- 首先实现远程对象类的接口: ```java package test.java;
import java.rmi.Remote; import java.rmi.RemoteException;
public interface RMIHelloInterface extends Remote { String hello() throws RemoteException; }
接口需要继承Remote接口,然后声明需要远程调用的方法.
> 为什么要实现接口,不实现行不行?
> 1. 不行, 不实现怎么给客户端调用?
2. 实现具体的远程对象类
实现接口的同时需要继承UnicastRemoteObject类
```java
package test.java;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class RMIHelloImpl extends UnicastRemoteObject implements Remote {
protected RMIHelloImpl() throws RemoteException {
super();
}
public String hello() throws RemoteException {
System.out.println("hello called!");
return "this is hello";
}
}
- 实现具体的Server,
Server要做的就是实例化远程对象并绑定到端口和name上.
package test.java;
import java.rmi.Naming;
import java.rmi.Remote;
import java.rmi.registry.LocateRegistry;
public class RMIServer {
public static void main(String[] args){
try {
// 创建一个RMI的注册中心
LocateRegistry.createRegistry(1234);
// 实例化RMI服务对象
Remote hello = new RMIHelloImpl();
// 绑定
Naming.rebind("rmi://127.0.0.1:1234/hello",hello);
} catch (Exception e){
e.printStackTrace();
}
}
}
- Client调用: ```java package test.java;
import java.rmi.Naming; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry;
public class RMIClient { public static void main(String[] args) { try { Registry registry = LocateRegistry.getRegistry(“127.0.0.1”,1234); // 获取所有注册的服务 String[] list = registry.list(); for(String i : list) { System.out.println(“service: “ + i); }
RMIHelloInterface hello = (RMIHelloInterface) Naming.lookup("rmi://127.0.0.1:1234/hello");
hello.hello();
} catch (Exception e) {
e.printStackTrace();
}
}
RMI 通信
可以参考 http://werner.yellowcouch.org/Lectures/javarmi/
通信的流程如下:
- 把Called Object注册到Registry
- Client连接Registry地址,然后发送一个Call消息
- Registry回复一个ReturnData消息,这个消息包含要调用对象的地址和端口
- Client再去连接远程调用对象的地址,然后远程对象返回执行结果
在第四步里面,涉及了一些序列化和反序列化:
具体的细节先不看,这些点都是攻击面
然后在这篇文章中讲解的序列化的点和反序列化的点很详细了: https://myzxcg.com/2021/10/Java-RMI%E5%88%86%E6%9E%90%E4%B8%8E%E5%88%A9%E7%94%A8/
- Server到RMIRegistry(步骤二)
- Client与RMIRegistry的双向通信(步骤三,四)
- Client调用远程方法(步骤六,九)
通信过程梳理: