- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
尝试使用 SSL 加密设置一个简单的 RMI 服务器。它适用于具有 Java 服务器应用程序和 Java 客户端应用程序的简单聊天应用程序,但是,目前我什至无法使用简单的 RMI 示例让它工作!
我能让它工作的唯一方法是客户端和服务器都具有相同的信任库和 keystore 。不过对我来说,这听起来不正确,因为这意味着每个客户端也有服务器的私钥。
我关注了this guide创建信任/ keystore 。我首先尝试生成一个 keystore 和信任库,然后用 keystore 运行服务器,用信任库运行客户端。这没有用,所以我随后为每个生成一对并加载,如下面的代码所示。
它认为我可能在某处遗漏了一些明显的东西,只是我终其一生都无法弄清楚自己做错了什么。我目前有以下内容,但是在运行服务器时我得到了 errors below :
错误:
Server exception: java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.rmi.transport.tcp.TCPChannel.createConnection(Unknown Source)
at sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
at sun.rmi.server.UnicastRef.newCall(Unknown Source)
at sun.rmi.registry.RegistryImpl_Stub.bind(Unknown Source)
at Server.main(Server.java:38)
Hello.java
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Hello extends Remote {
String sayHello() throws RemoteException;
}
服务器.java
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;
public class Server extends UnicastRemoteObject implements Hello {
private static final long serialVersionUID = 5186776461749320975L;
protected Server(int port) throws IOException {
super(port, new SslRMIClientSocketFactory(), new SslRMIServerSocketFactory(null, null, true));
}
@Override
public String sayHello() {
return "Hello, world!";
}
public static void main(String[] args) throws RemoteException, IllegalArgumentException {
try {
setSettings();
Server server = new Server(2020);
LocateRegistry.createRegistry(2020, new SslRMIClientSocketFactory(), new SslRMIServerSocketFactory(null, null, true));
System.out.println("RMI registry running on port " + 2020);
Registry registry = LocateRegistry.getRegistry("DAVE-PC", 2020, new SslRMIClientSocketFactory());
registry.bind("Hello", server);
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
private static void setSettings() {
String pass = "password";
System.setProperty("javax.net.ssl.debug", "all");
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\serverkeystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", pass);
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\servertruststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", pass);
}
}
客户端.java
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import javax.rmi.ssl.SslRMIClientSocketFactory;
public class Client {
private Client() {}
public static void main(String[] args) {
try {
setSettings();
Registry registry = LocateRegistry.getRegistry("DAVE-PC", 2020, new SslRMIClientSocketFactory());
Hello hello = (Hello) registry.lookup("Hello");
String message = hello.sayHello();
System.out.println(message);
} catch (Exception e) {
System.err.println("Client exception: " + e.toString());
e.printStackTrace();
}
}
private static void setSettings() {
String pass = "password";
System.setProperty("javax.net.ssl.debug", "all");
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\clientkeystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", pass);
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\clienttruststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", pass);
}
}
最佳答案
PKIX 错误意味着客户端不信任服务器证书,在这种情况下服务器是注册表。
澄清一下,您需要两个私钥和两个 keystore 来保存它们,每个一个。然后您需要在每个 keystore 中创建证书、导出它们并将它们导入到对等方的信任库中。服务器的信任库必须信任客户端的 keystore ,反之亦然。
您的代码看起来基本没问题。 createRegistry() 的结果应该存储在一个静态变量中,以防止它被 GC。无论您的 IDE 告诉您什么,您都不需要服务器类中的 serialVersionUID。它不会被序列化,至少不会被 RMI 序列化。
编辑 问题在这里:
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-server.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-client.jks");
应该是:
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-server.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-server.jks");
这里:
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-client.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-server.jks"
应该是:
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-client.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-client.jks"
编辑 2 根本问题是绑定(bind)到注册表时所需的信任库是客户端信任库,但运行服务器时所需的信任库是服务器信任库。
至少有三种可能的解决方案,按优劣顺序排列:
设置一个 SslRMIClientSocketFactory
的子类,它有自己的 SSLContext
和它自己的从客户端信任库加载的 TrustManager
,并覆盖 创建套接字()
。哎哟。
同时将服务器的证书导入服务器的信任库。
使用 createRegistry()
的返回值来执行 bind()
而不是在服务器中调用 getRegistry()
完全避免,并避免整个问题。
关于java - 带 SSL 的简单 RMI 服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21586660/
我正在编写一个 RMI 应用程序。 我能够执行 RMI。数据通过 RMI 在客户端和服务器之间传输。 客户端应始终接收/更新服务器端数据。 是否有可能有一个监听器可以将数据更新/修改从服务器传输或通知
我正在使用 JMX-RMI 代理进行消息传递。我有一个 java 程序,它向一组监听器/监听器发送一条具有名称/ID 的消息。根据监听器收到的消息,客户端程序会相应地运行。这篇文章工作正常,但我想知道
我有一个 RMI 服务器,当在本地主机上运行时,它可以正确绑定(bind)到 RMI 注册表(以证明设置正确)。执行此操作的代码是: private void exposeTickHistoryRe
我想获取服务器端每个客户端的 ip 地址,服务器为其返回一个 stub 。是否可以? 最佳答案 请参阅 RemoteServer.getClientHost()。您可以在远程方法实现中调用它。但是,当
我有两个 Java 程序 - RMIServer 和 RMIClient。如果我将它们作为两个单独的 Java 调用启动,一切都会按预期工作。那就是 $ java -cp someclasspath
目前正在阅读有关 RPC 和 RMI 的资料,我对它们之间的区别有点困惑。 在实现 RMI 和 gRPC 时,语法基本相同。 它们都有确定方法参数和响应的接口(interface)。 它们都可以在参数
这个问题在这里已经有了答案: 12年前关闭。 Possible Duplicate: RMI and CORBA Differences? RMI 和 Corba 有什么区别? 最佳答案 RMI 是一
我是 java RMI 的新手,我正在尝试创建一个类似 Peer 2 Peer 的 bit torrent 应用程序,其中同一对等点的多个实例可能位于同一台机器上。这意味着我需要能够在同一台机器上注册
当我尝试运行我的 RMI 示例时出现远程异常。我不明白为什么。我在不对程序本身或 JVM 进行任何参数的情况下运行该程序。 请帮助我摆脱异常。 非常感谢 这是我得到的异常: Server except
关于 Oracle's FAQ page关于 Java RMI,它说: While the Java Remote Method Invocation (Java RMI) server can th
我有一个 java rmi 服务器和一个 java rmi 客户端在两台独立且不同的机器。 服务器基本上是一个斐波那契计算器。它接收一堆数字并根据它们计算斐波那契数列。 客户端只需发送一堆数字供服务器
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 8 年前。 Improve th
我想知道 RMI 中是否可以在与提供服务的服务器不同的主机上启动 RMIregistry。 最佳答案 是的,这是可能的,但不方便,因为bind()、rebind()和unbind()只能从本地主机接受
我在连接客户端类的远程对象时遇到一些问题。当我运行以下客户端类时,我收到 java.rmi.ConnectException。 import java.rmi.registry.LocateRegis
我正在尝试让一台计算机上的客户端通过 Java RMI 与另一台计算机上的服务器通信。我将服务器部署在端口 Y 上的主机 IP X 上。然后,我尝试让客户端查找服务器上的远程对象,但出现以下异常: E
我有一个自定义的 RMIClientSocketFactory,它覆盖“createSocket”来创建一个特殊的套接字。 如何在我的 rmi 远程接口(interface)实现中获取这个套接字? (
我的 RMI Reaper 线程有问题,它不允许我的所有程序终止,因为该线程不是守护进程。我发现信息表明该线程仅在所有对象均未导出时停止。所以我有以下代码来创建 rmi serer。 registry
当我在运行 RMI 服务器后尝试运行 RMI 客户端时,出现以下异常: EncodeInterface exception: java.lang.ClassCastException: $Proxy3
我想为 RMI 客户端应用程序编写一组系统集成测试。我想在 JUnit 3.8.2 中启动 RMI 服务器,然后运行这些测试。有没有人这样做过? 我在带有 main 的 pojo 中使用类似这样的东西
这个问题已经有答案了: java.rmi.ServerException: RemoteException occurred in server thread (ClassNotFoundExcept
我是一名优秀的程序员,十分优秀!