2017-03-01 19 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"도 있습니다. 서버를 시작하는 데몬과 서버를 종료하는 서버에 모두 액세스 할 수 있습니다.

데몬 클래스 : 내 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됩니다.

웹 서치 나에게이 문제를 해결하는 방법에 대한 아이디어를 포기하지 않았다 ...하지만 어쩌면 내가 잘못된 방향으로 찾고 있어요 ...

어떤 도움이 크게 감사하고 나는 미리 사람을 감사합니다! :)

답변

0

이미 언급 한 바와 같이 배치 작업 중에 "CTRL + C"를 누르면 (데몬이 cmd 파일에서 bat 파일을 실행하면서 시작됨) JVM과 서버 JVM에서 작성된 레지스트리가 모두 종료됩니다 아래로.

내 문제를 해결하기 위해 자체 ShutDownProcedure를 시작할 서버에 ShutDownHook을 추가했습니다. 불행히도 완전히 다른 "숨겨진"cmd-window를 시작하고 ProcessBuilder를 사용하여 다른 jar-application을 시작하는 좋은 방법을 찾지 못했습니다.

EJP의 조언 덕분에 코드에서 레지스트리 생성 부분을 제거하고 배치 파일에서 시작했습니다.

1

이것은 모두 무의미합니다. 전체 JVM을 종료합니다. 그러면 JVM에서 작성한 레지스트리가 모든 바인딩과 함께 사용됩니다. 실제로 레지스트리는 귀하의 lookup() 통화 도중 이미 종료되었습니다.

종료 훅을 제거하기 만하면됩니다.

원격 개체 인 경우 레지스트리를 조회 할 필요가 없습니다. 당신이 필요로하는 것은 바인딩을 풀고 자신을 unexport하는 것이 었습니다. 그러나 당신은 그것조차 필요하지 않습니다.

+0

JVM을 종료하면 레지스트리가 종료되지만이 경우 자체는 조회되지 않지만 내 보낸 서버 객체는 종료됩니다. 서버는 데몬이 시작한 별도의 JVM에서 실행됩니다. 문제는 실제로 내 데몬이 "cmd.exe"에서 시작되고 데몬 내부에서 시작된 서버가 데몬과 동일한 창을 사용한다는 것입니다. 따라서 "CTRL + C"를 누르면 JVM이 종료됩니다. 서버에는 후크가 없으므로 데몬이 액세스하기 전에 서버 레지스트리가 다운 된 것으로 추측됩니다. 그리고 getRegistry는 그것이 존재하는지 검사하지 않기 때문에 그 라인에서 예외를 설명 할 것이다.감사합니다 :) – motaa

+0

아, 그리워. 동일한 JVM에서'Server'를 실행하면 모든 malarkey가 제거됩니다. 두 개의 JVM에서해야한다면,'LocateRegistry.getRegistry()'가 아닌'this.reg'를 통해 종료 훅을 검색해야합니다. 그 이유는'this.reg'는 스텁이 아닌 실제 레지스트리 구현 객체이므로 unexport되거나 I/O 스레드가 종료 되어도 조회가 계속 작동하기 때문입니다. – EJP

+0

나는 당신의 요지 인 @EJP를보고 있지만, 서버는 앞으로의 변경을 위해 자체 JVM을 가져야 만한다. 'this.reg'를 사용하여 ref를 작성합니다. JVM 용 데몬 reg (1). 그 아이디어는 JVM (2)에서 서버의 reg를 얻고, 서버 객체를 찾아서 종료를 시작하고, 즉시 반환하고 데몬이 끝내게하는 것입니다. 데몬 레지스트리에 서버 개체를 등록 할 수 있으므로 한 번만 처리하면됩니다. 하지만 서버에서 데몬 훅을 잃어버린 경우 좀비 프로세스가 생깁니다. 새로운 서버를 시작할 때 나는 그것을 처리합니다. 서버 reg를 사용하여 나는 나의 GUI에서 "zombie-server"에 대한 제어권을 가지고있다. :) – motaa