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

RMI;JRMP连接错误;由连接重置引起,rmi,jrmp,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

我得到了以下异常,我不明白为什么会发生这种情况

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上侦听的注册表,而服务器有一个在post 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时,在尝试查找导出的服务器对象时抛出了提到的异常

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


非常感谢您的帮助,我提前向您表示感谢!:)

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

只需卸下关机挂钩


在任何情况下,如果您自己是远程对象,则无需查找注册表即可找到自己。你所需要的只是解开你的绑,然后把你自己解开。但是您甚至不需要它。

如注释中所述,在批处理作业(守护进程是从执行bat文件的cmd启动的)期间,按“CTRL+C”将关闭两个JVM,因此在服务器JVM中创建的注册表也将关闭

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


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

我确实知道关闭JVM会杀死注册表,但在这种情况下,我不会查找注册表本身,而是查找导出的服务器对象。服务器在守护进程启动的单独JVM中运行。我认为问题实际上是我的守护进程从“cmd.exe”启动,从守护进程内部启动的服务器也使用与守护进程相同的窗口。因此,点击“CTRL+C”将关闭两个JVM。由于服务器没有任何挂钩,我猜在守护进程可以访问它之前,服务器注册表已经关闭。由于getRegistry没有检查它是否存在,这将解释这一行的异常。谢谢:)啊,好的,没有看到。我将在同一个JVM中运行
Server
,这将消除所有的恶意行为。如果必须在两个JVM中执行此操作,则应通过
this.reg
在关机挂钩中查找,而不是通过
LocateRegistry.getRegistry()
。原因是
this.reg
是实际的注册表实现对象,而不是存根,因此即使它未被报告或其I/O线程已退出,查找仍将工作。我明白您的观点@EJP,但服务器必须有自己的JVM才能进行更改。使用
this.reg
我将引用JVM的守护程序reg(1)。其思想是在JVM(2)中获取服务器的注册表,查找服务器对象并启动关机,立即返回并让守护进程完成。我发现我可以将服务器对象注册到Daemon reg,这样我就只需要处理一个。但是如果我丢失了服务器上的守护进程钩子,我将有一个僵尸进程。不过,我在启动新服务器时会处理这个问题。使用服务器注册,我可以从GUI控制“僵尸服务器”:坚持您不需要两个注册表。端口1099上JVM 1中的一个就足够了。如果您想变得健壮,请启动
rmiregistry
命令行实用程序。它从不崩溃。或者使用激活。