day2—java_RMI

基础

Remote

一个interface(抽象方法),该interface中没有申明任何方法,但是只有继承该接口才可以被远程调用

1
2
3
4
5
6
7
8
9
package rmi;

import java.io.IOException;
import java.rmi.Remote;

public interface Rmi extends Remote {
public String hello() throws IOException;
}

RemoteException

RemoteException是所有在远程调用中所抛出异常的超类,所有能够被远程调用的方法声明,都需要抛出此异常

Naming

提供向注册中心保存远程对象引用或者从注册中心获取远程对象引用的方法。这个类中的方法都是静态方法,每一个方法都包含了一个类型为String的name参数, 这个参数是URL格式,形如://host:port/name

1
2
3
4
5
6
7
8
9
import java.rmi.Naming;

public class ClientDemo {
public static void main(String[] args) throws Exception{
Naming.lookup("rmi://127.0.0.1:1099/rmi");
String hello = rmi.hello();
System.out.println(hello);
}
}

Registry

一个interface, 其功能和Naming类似,每个方法都有一个String类型的name参数,但是这个name不是URL格式,是远程对象的一个命名。Registry的实例可以通过方法LocateRegistry.getRegistry()获得

1
2
3
4
5
6
7
8
9
10
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class ClientDemo {
public static void main(String[] args) throws Exception{
Registry registry = LocateRegistry.getRegistry("127.0.0.1",1099);
Rmi rmi1 = (Rmi) registry.lookup("rmi");
System.out.println(rmi1.hello());
}
}

LocateRegistry

用于获取到注册中心的一个连接,这个连接可以用于获取一个远程对象的引用。也可以创建一个注册中心。

1
2
Registry registry = LocateRegistry.createRegistry(1099);
Registry registry = LocateRegistry.getRegistry("127.0.0.1",1099);

RemoteObject

重新覆写了Object对象中的equals,hashCode,toString方法,从而可以用于远程调用

UnicastRemoteObject

用于RMI Server中导出一个远程对象并获得一个stub。这个stub封装了底层细节,用于和远程对象进行通信。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.io.IOException;
import java.io.InputStream;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class RemoteHelloworld extends UnicastRemoteObject implements Rmi{
@Override
public String hello() throws IOException {
Runtime runtime = Runtime.getRuntime();
InputStream in = runtime.exec("id").getInputStream();
byte[] bytes = new byte[1024];
in.read(bytes);
return new String(bytes);
}
protected RemoteHelloworld() throws RemoteException {
super();
}

}

Unreferenced

一个interface, 声明了方法:void unreferenced()如果一个远程对象实现了此接口,则这个远程对象在没有任何客户端引用的时候,这个方法会被调用。

服务端

服务端为kali

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
rmi
├── RemoteHelloworld.java
├── Rmi.java
└── Servet.java

//RemoteHelloworld.java
package rmi;

import java.io.IOException;
import java.io.InputStream;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class RemoteHelloworld extends UnicastRemoteObject implements Rmi{
public String hello() throws IOException {
Runtime runtime = Runtime.getRuntime();
InputStream in = runtime.exec("id").getInputStream();
byte[] bytes = new byte[1024];
in.read(bytes);
return new String(bytes);
}
protected RemoteHelloworld() throws RemoteException {
super();
}
}



//Rmi.java
package rmi;

import java.io.IOException;
import java.rmi.Remote;

public interface Rmi extends Remote {
public String hello() throws IOException;
}


//Servet.java
package rmi;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class Servet {
public static void main(String[] args) throws Exception {
Rmi rmi = new rmi.RemoteHelloworld();
Registry registry = LocateRegistry.createRegistry(1099);
System.out.println("rmi server already start");
registry.rebind("rmi",rmi);
}
}

  • 踩坑指南

    显示连接超时,大概率是因为服务端/etc/hosts 指定的除localhost之外的映射是一个内网网址,网上给出了几种解决方案,

    第一种 删除/etc/hosts对应记录

    第二种 运行时增加-Djava.rmi.server.hostname=服务器真实外网IP参数

    第三种 服务端代码中增加System.setProperty(“java.rmi.server.hostname”,”外网IP”);

    但是使用上面三种都无法解决我的问题,最终将/etc/hosts中映射地址改为公网地址

    image-20211013110803852

客户端

客户端为Mac

客户端目录结构应该与服务端保持一致,并且客户端与服务端都应该有相同的Remote接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
rmi
├── ClientDemo.java
└── Rmi.java

//ClientDemo.java
package rmi;

import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class ClientDemo {
public static void main(String[] args) throws Exception{
// Rmi rmi = (Rmi) Naming.lookup("rmi://172.16.173.2:1099/rmi");
// String hello = rmi.hello();
// System.out.println(hello);
//
Registry registry = LocateRegistry.getRegistry("172.16.173.2",1099);
Rmi rmi1 = (Rmi) registry.lookup("rmi");
System.out.println(rmi1.hello());
}
}

//Rmi.java
package rmi;

import java.rmi.Remote;

public interface Rmi extends Remote {
public String hello() throws Exception;
}

最终成功利用image-20211013110947505