0

我得到以下异常,我无法弄清楚为什么会发生这种情况。

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

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

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

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

守护进程类:

//.....
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 时,在尝试查找导出的服务器对象时会引发上述异常。

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

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

4

2 回答 2

1

这都是没有意义的。您正在关闭整个 JVM。这将使用您在 JVM 中创建的注册表以及所有绑定。事实上,显然注册表在您lookup()通话期间已经退出。

只需删除您的关机钩子。

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

于 2017-03-01T11:46:15.327 回答
0

正如评论中已经说明的那样,在批处理作业期间点击“CTRL+C”(守护进程正在从 cmd 执行一个 bat 文件启动)会关闭两个 JVM,因此在服务器 JVM 中创建的注册表也会关闭。

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

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

于 2017-03-13T09:00:09.217 回答