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. В этом Daemon у меня есть 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 я получаю доступ к удаленному объекту Server точно так же, как и из Daemon, а также могу без проблем вызвать метод killServer(). Но когда я нажимаю CTRL+C, чтобы запустить ShutDownHook из Daemon, упомянутое исключение выдается при попытке поиска экспортированного объекта Server.

Веб-поиск не дал мне никаких идей о том, как решить эту проблему... но, возможно, я смотрю не в ту сторону...

Любая помощь очень ценится, и я благодарю всех заранее!:)

2 ответа

Решение

Как уже говорилось в комментариях, нажатие клавиши "CTRL+C" во время пакетного задания (демон запускается из cmd, выполняющего bat-файл) отключает обе JVM, и, таким образом, также отключается реестр, созданный на JVM сервера.

Чтобы решить мою проблему, я просто добавил ShutDownHook на сервер, который будет запускать свой собственный ShutDownProcedure. К сожалению, я не нашел хорошего способа запустить совершенно отдельное "невидимое" cmd-окно и запустить другое jar-приложение, используя ProcessBuilder.

Благодаря совету EJP я удалил часть создания реестра из кода и запустил ее из командного файла.

Это все бессмысленно. Вы закрываете всю JVM. Это возьмет с собой Реестр, который вы создали в вашей JVM, вместе со всеми привязками. На самом деле, очевидно, что реестр уже вышел во время вашего lookup() вызов.

Просто удалите свой крюк отключения.

В любом случае, если вы сами являетесь удаленным объектом, вам не нужно искать реестр, чтобы найти себя. Все, что вам было нужно, это расстегнуть, а затем удалить себя. Но тебе это даже не нужно.

Другие вопросы по тегам