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

时间:2017-03-01 11:18:10

标签: rmi jrmp

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

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

我有一个Daemon类负责在单独的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时,在尝试查找导出的Server对象时会抛出提到的异常。

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

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

2 个答案:

答案 0 :(得分:1)

This is all pointless. You're shutting down the entire JVM. That will take the Registry you created in your JVM with it, along with all the bindings. In fact obviously the Registry has already exited during your lookup() call.

Just remove your shutdown hook.

In any case if you are the remote object yourself, you don't need to lookup the Registry to find yourself. All you needed was to unbind and then unexport yourself. But you don't even need that.

答案 1 :(得分:0)

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

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

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