2017-03-01 123 views
0

我得到以下异常,我无法弄清楚为什么会发生。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 

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

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

现在我也有一个“ClientGui”,可以关闭服务器并重新启动它。它可以访问Daemon以启动服务器,并通过服务器将其关闭。

守护类:

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

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

任何帮助是极大的赞赏,我感谢任何人提前! :)

回答

0

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

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

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

1

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

只要删除您的关机挂钩。

在任何情况下,如果您自己是远程对象,则无需查找注册表以查找自己。所有你需要的是解除绑定然后导出自己。但你甚至不需要那个。

+0

我得到关闭JVM杀死注册表,但在这种情况下,我不查找它本身,但导出的服务器对象。服务器在由守护程序启动的单独JVM中运行。我认为问题实际上是我的守护进程从“cmd.exe”开始,并且从守护进程内启动的服务器也使用与守护进程相同的窗口。因此点击“CTRL + C”会关闭这两个JVM。由于服务器没有任何挂钩,我猜服务器注册表在Daemon可以访问它之前就关闭了。并且由于getRegistry不检查它是否存在会解释该行的异常。谢谢:) – motaa

+0

啊OK错过了。我会在同一个JVM中运行'Server',这将消除所有的malarkey。如果您必须在两个JVM中执行此操作,则应该通过'this.reg'在shutdown hook中查找,而不是通过'LocateRegistry.getRegistry()'查找。原因是'this.reg'是实际的Registry实现对象,而不是存根,所以即使它已被取消导出或其I/O线程已退出,查找仍然有效。 – EJP

+0

我看到你的观点@EJP,但服务器必须有它自己的JVM来接受更改。使用'this.reg'我会参考。 JVM的守护程序(1)。这个想法是在JVM(2)中获取服务器的reg,查找服务器对象并启动关闭,立即返回并让Daemon完成。我发现我可以将服务器对象注册到守护进程,因此我只需要处理一个。但是如果我在服务器上失去了守护进程钩子,我会有一个僵尸进程。不过,我在开始使用新服务器时会处理这个问题。使用服务器注册我一直控制着来自我的GUI的“僵尸服务器”。 :) – motaa