RMI: 远程方法调用(Remote Method Invocation),用于不同虚拟机之间的通信,这些虚拟机可以在不同的主机上、也可以在同一个主机上;一个虚拟机中的对象调用另一个虚拟上中的对象的方法。

RMIDemo

服务端组成的三个部分

创建一个继承java.rmi.Remote的接口(RMIInterface),定义需要远程调用的函数(HelloWorld())

一个实现此接口的类(RemoteHelloWorld),在服务端实现接口定义的代码。

一个主类(RMIServer)用于创建Registry,绑定类示例

RMIInterface

1
2
3
4
5
6
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface RMIInterface extends Remote {
String HelloWorld() throws RemoteException;
}

RemoteHelloWorld

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class RemoteHelloWorld extends UnicastRemoteObject implements RMIInterface{

protected RemoteHelloWorld() throws RemoteException {
super();
}

@Override
public String HelloWorld() throws RemoteException {
return "HelloWorld";
}
}

RMIServer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;

public class RMIServer {
//服务端ip
public static final String RMIHost = "192.168.47.128";
//服务端端口
public static final int RMIPort = 1099;
//服务端名称
public static final String RMIName = "rmi://" + RMIHost + ":" + RMIPort + "/HelloWorld";

public static void main(String[] args) throws RemoteException, MalformedURLException, AlreadyBoundException {
//注册端口
LocateRegistry.createRegistry(RMIPort);
//绑定实例对象
Naming.bind(RMIName, new RemoteHelloWorld());
System.out.println("RMIServer created, ip address:" + RMIName);
}

}

客户端

RMIClient

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;


public class RMIClient {

public static void main(String[] args) throws MalformedURLException, NotBoundException, RemoteException {
// 查找远程RMI服务,lookup获取远程对象。
RMIInterface rt = (RMIInterface) Naming.lookup("rmi://192.168.47.1:1099/HelloWorld");
// 调用远程接口RMIInterface类的HelloWord方法
String result = rt.HelloWorld();
System.out.println(result);
}
}

运行测试

服务端47.1

image-20220309152824177

客户端47.128

image-20220309154945907

47.12847.1第一次握手之后,客户端向服务端发送一个Call数据包,服务端回一个ReturnData数据包

image-20220309160111143

ReturnData数据包中,ac ed往后为反序列化内容。

image-20220309160531079

修改客户端代码rebind() HelloWorld方法

1
2
3
4
5
6
7
8
9
public class RMIClient {

public static void main(String[] args) throws MalformedURLException, NotBoundException, RemoteException {
Naming.rebind("rmi://192.168.47.1:1099/HelloWorld",new RemoteHelloWorld());
RMIInterface rt = (RMIInterface) Naming.lookup("rmi://192.168.47.1:1099/HelloWord");
String result = rt.HelloWorld();
System.out.println(result);
}
}

报错如下

image-20220309164618851

只有源地址是本地才可调用rebind,bind,unbindlist,lookup可远程调。