2017-03-01 15 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」もあります。サーバーを起動するデーモンとサーバーをシャットダウンするサーバーの両方にアクセスできます。

デーモンクラス:

//..... 
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を起動すると、エクスポートされたServerオブジェクトをルックアップしようとすると、上記の例外がスローされています。

ウェブ検索は私にこの問題を解決する方法上の任意のアイデアを与えていない...しかし、多分私は間違った方向に探しています...

すべてのヘルプは大歓迎ですが、私は事前に誰に感謝します! :)

答えて

0

バッチジョブ中に "CTRL + C"を押すと(バートファイルを実行するcmdからデーモンが起動されている)、JVMの両方がシャットダウンされ、サーバーJVMで作成されたレジストリがシャットダウンしますダウンも同様に。

私の問題を解決するために、シャドウダウンをサーバーに追加しました。シャットダウンは独自のシャットダウン手順を開始します。残念ながら、私は完全に別の "隠されていない" cmd-windowを開始し、ProcessBuilderを使用して別のjarアプリケーションを開始する良い方法は見つけられていません。

EJPのアドバイスのおかげで、レジストリの作成部分がコードから削除され、バッチファイルから起動されました。

1

これはすべて無意味です。 JVM全体をシャットダウンしています。これで、JVMで作成したレジストリが、すべてのバインディングと共に取得されます。事実、明らかにレジストリはあなたのlookup()呼び出し中に終了しました。

シャットダウンフックを取り外すだけです。

あなたがリモートオブジェクトである場合は、自分自身を見つけるためにレジストリをルックアップする必要はありません。あなたが必要としたのは、アンバインドして自分自身をアンエクスポートすることでした。しかし、あなたはそれを必要としません。

+0

JVMをシャットダウンするとレジストリが強制終了されますが、この場合は自分自身を検索するのではなく、エクスポートされたサーバオブジェクトを検索します。サーバーは、デーモンによって起動された別個のJVMで実行されます。私の問題は実際に私のデーモンは "cmd.exe"から起動し、デーモン内から起動されたサーバはデーモンと同じウィンドウを使用するということです。したがって、 "CTRL + C"を押すと、両方のJVMがシャットダウンされます。サーバーはフックを持っていないので、デーモンがアクセスする前にサーバレジストリがダウンしていると思います。そして、getRegistryはそれが存在するかどうかをチェックしないので、その行で例外が説明されます。ありがとう:) – motaa

+0

ああ、それを逃した。同じJVMで 'Server'を実行すると、すべてのmalarkeyが削除されます。 2つのJVMで実行する必要がある場合は、 'LocateRegistry.getRegistry()'ではなく、 'this.reg'を介してシャットダウンフックを参照する必要があります。なぜなら、 'this.reg'は実際のレジストリ実装オブジェクトであり、スタブではないため、アンエクスポートされているか、I/Oスレッドが終了してもルックアップが機能するからです。 – EJP

+0

あなたのポイント@EJPが表示されますが、サーバーには変更が来るために独自のJVMが必要です。 'this.reg'を使って私は参考にします。 JVMのデーモンreg(1)。アイデアは、JVM(2)でサーバーのregを取得し、サーバーオブジェクトを検索してシャットダウンを開始し、すぐに戻り、デーモンに完了させることです。私はデーモンregにサーバーオブジェクトを登録することができるので、私は1つしか扱わないことになります。しかし、私がサーバー上でデーモンフックを失った場合、私はゾンビプロセスを持っています。私は新しいサーバーを起動するときにそれを処理します。サーバーregを使用して、私は自分のGUIから "ゾンビサーバー"を制御し続けます。 :) – motaa

関連する問題