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()
вызов.
Просто удалите свой крюк отключения.
В любом случае, если вы сами являетесь удаленным объектом, вам не нужно искать реестр, чтобы найти себя. Все, что вам было нужно, это расстегнуть, а затем удалить себя. Но тебе это даже не нужно.