다음 예외가 발생하며 그 이유를 알 수 없습니다.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"도 있습니다. 서버를 시작하는 데몬과 서버를 종료하는 서버에 모두 액세스 할 수 있습니다.
데몬 클래스 : 내 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();
}
}
}
}
내가 데몬에서와 완전히 같은 방법으로 원격 서버 개체에 액세스하고도 문제없이 killServer() 메서드를 호출 할 수 있습니다. 그러나 Ctrl + C를 눌러 데몬에서 ShutDownHook을 시작하면 내 보낸 Server 개체를 조회 할 때 언급 된 예외가 throw됩니다.
웹 서치 나에게이 문제를 해결하는 방법에 대한 아이디어를 포기하지 않았다 ...하지만 어쩌면 내가 잘못된 방향으로 찾고 있어요 ...
어떤 도움이 크게 감사하고 나는 미리 사람을 감사합니다! :)
JVM을 종료하면 레지스트리가 종료되지만이 경우 자체는 조회되지 않지만 내 보낸 서버 객체는 종료됩니다. 서버는 데몬이 시작한 별도의 JVM에서 실행됩니다. 문제는 실제로 내 데몬이 "cmd.exe"에서 시작되고 데몬 내부에서 시작된 서버가 데몬과 동일한 창을 사용한다는 것입니다. 따라서 "CTRL + C"를 누르면 JVM이 종료됩니다. 서버에는 후크가 없으므로 데몬이 액세스하기 전에 서버 레지스트리가 다운 된 것으로 추측됩니다. 그리고 getRegistry는 그것이 존재하는지 검사하지 않기 때문에 그 라인에서 예외를 설명 할 것이다.감사합니다 :) – motaa
아, 그리워. 동일한 JVM에서'Server'를 실행하면 모든 malarkey가 제거됩니다. 두 개의 JVM에서해야한다면,'LocateRegistry.getRegistry()'가 아닌'this.reg'를 통해 종료 훅을 검색해야합니다. 그 이유는'this.reg'는 스텁이 아닌 실제 레지스트리 구현 객체이므로 unexport되거나 I/O 스레드가 종료 되어도 조회가 계속 작동하기 때문입니다. – EJP
나는 당신의 요지 인 @EJP를보고 있지만, 서버는 앞으로의 변경을 위해 자체 JVM을 가져야 만한다. 'this.reg'를 사용하여 ref를 작성합니다. JVM 용 데몬 reg (1). 그 아이디어는 JVM (2)에서 서버의 reg를 얻고, 서버 객체를 찾아서 종료를 시작하고, 즉시 반환하고 데몬이 끝내게하는 것입니다. 데몬 레지스트리에 서버 개체를 등록 할 수 있으므로 한 번만 처리하면됩니다. 하지만 서버에서 데몬 훅을 잃어버린 경우 좀비 프로세스가 생깁니다. 새로운 서버를 시작할 때 나는 그것을 처리합니다. 서버 reg를 사용하여 나는 나의 GUI에서 "zombie-server"에 대한 제어권을 가지고있다. :) – motaa