RMI; JRMP连接错误;由连接重置引起

RMI; JRMP connection error; Caused by connection reset

我收到以下异常,我不明白为什么会这样。

java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is: java.net.SocketException: Connection reset
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.lookup(Unknown Source)
at Daemon$ShutDownProcedure.run(Daemon.java:126)
Caused by: java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.io.BufferedInputStream.fill(Unknown Source)
at java.io.BufferedInputStream.read(Unknown Source)
at java.io.DataInputStream.readByte(Unknown Source)
... 5 more

我有一个守护进程 class 负责在单独的 JVM 中启动服务器。在那个守护进程中,我有一个 ShutDownHook 调用远程服务器对象上的方法,该方法在服务器上启动关闭过程。

守护进程本身也是一个导出的 RMI 对象,但在不同的端口上,以便我可以远程启动服务器。 这意味着守护进程已经创建了一个监听端口 1099 的注册表,并且服务器有一个监听 post 1098.

的注册表

现在我还有一个 "ClientGui" 可以关闭服务器并重新启动它。它既可以访问守护进程来启动服务器,也可以访问服务器来关闭它。

守护进程class:

//.....
private Daemon(String[] args){
    try {
        this.reg = LocateRegistry.createRegistry(1099);
        this.stub = (DaemonRemote) UnicastRemoteObject.exportObject(this, 1099);
        this.reg.rebind(DaemonRemote.class.getName(), this.stub);   
        this.arguments = args;
        Runtime.getRuntime().addShutdownHook(new ShutDownProcedure());          
    } catch (RemoteException e) {
        e.printStackTrace();
    }       
}

//....
public static void main(String[] args){             

  String initialargs = Arrays.stream(args).collect(Collectors.joining(" "));
  String[] command = new String[] {"java", "-Xmx4g","-cp", System.getProperty("java.class.path", "."), Server.class.getName(),initialargs};

  try {
    p = new ProcessBuilder(command).inheritIO().redirectErrorStream(true).start();          
    } catch (Exception e) {
      e.printStackTrace();  
    }       
    if(daemon == null)
        daemon = new Daemon(args);
}
//....
private class ShutDownProcedure extends Thread {

    @Override
    public void run(){      

        if(p.isAlive()){
          try {
            Registry serverreg = LocateRegistry.getRegistry(null, 1098);
            ServerRemote serverrmi = (ServerRemote) serverreg.lookup(ServerRemote.class.getName()); //this is the line where the exception occurs...
            serverrmi.killServer();
          } catch (IOException | NotBoundException | InterruptedException e) {          
            e.printStackTrace();
        }
    }
}

}

我从 ClientGui 访问远程服务器对象的方式与从守护进程访问远程服务器对象的方式完全相同,而且还可以毫无问题地调用 killServer() 方法。但是,当我按 CTRL+C 从守护程序启动 ShutDownHook 时,在尝试查找导出的服务器对象时会抛出上述异常。

网络搜索没有给我任何关于如何解决这个问题的想法......但也许我找错了方向......

非常感谢任何帮助,我提前感谢任何人! :)

这一切都毫无意义。您正在关闭整个 JVM。这将带走您在 JVM 中创建的注册表以及所有绑定。事实上,在您的 lookup() 调用期间,注册表显然已经退出。

只需删除您的关闭挂钩。

无论如何,如果您自己就是远程对象,则无需查找注册表即可找到您自己。您所需要的只是解除绑定,然后取消导出自己。但你甚至不需要那个。

如评论中所述,在批处理作业期间点击 "CTRL+C"(守护进程从执行 bat 文件的 cmd 启动)会关闭两个 JVM,从而关闭在服务器 JVM 中创建的注册表也关闭了。

为了解决我的问题,我刚刚向服务器添加了一个 ShutDownHook,它将启动自己的 ShutDownProcedure。不幸的是,我还没有找到启动一个完全独立的 "unhidden" cmd-window 并使用 ProcessBuilder 启动另一个 jar 应用程序的好方法。

感谢 EJP 的建议,我从代码中删除了注册表创建部分并从批处理文件启动它。