次の例外が発生しましたが、なぜそれが起こっているのかわかりません。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オブジェクトをルックアップしようとすると、上記の例外がスローされています。
ウェブ検索は私にこの問題を解決する方法上の任意のアイデアを与えていない...しかし、多分私は間違った方向に探しています...
すべてのヘルプは大歓迎ですが、私は事前に誰に感謝します! :)
JVMをシャットダウンするとレジストリが強制終了されますが、この場合は自分自身を検索するのではなく、エクスポートされたサーバオブジェクトを検索します。サーバーは、デーモンによって起動された別個のJVMで実行されます。私の問題は実際に私のデーモンは "cmd.exe"から起動し、デーモン内から起動されたサーバはデーモンと同じウィンドウを使用するということです。したがって、 "CTRL + C"を押すと、両方のJVMがシャットダウンされます。サーバーはフックを持っていないので、デーモンがアクセスする前にサーバレジストリがダウンしていると思います。そして、getRegistryはそれが存在するかどうかをチェックしないので、その行で例外が説明されます。ありがとう:) – motaa
ああ、それを逃した。同じJVMで 'Server'を実行すると、すべてのmalarkeyが削除されます。 2つのJVMで実行する必要がある場合は、 'LocateRegistry.getRegistry()'ではなく、 'this.reg'を介してシャットダウンフックを参照する必要があります。なぜなら、 'this.reg'は実際のレジストリ実装オブジェクトであり、スタブではないため、アンエクスポートされているか、I/Oスレッドが終了してもルックアップが機能するからです。 – EJP
あなたのポイント@EJPが表示されますが、サーバーには変更が来るために独自のJVMが必要です。 'this.reg'を使って私は参考にします。 JVMのデーモンreg(1)。アイデアは、JVM(2)でサーバーのregを取得し、サーバーオブジェクトを検索してシャットダウンを開始し、すぐに戻り、デーモンに完了させることです。私はデーモンregにサーバーオブジェクトを登録することができるので、私は1つしか扱わないことになります。しかし、私がサーバー上でデーモンフックを失った場合、私はゾンビプロセスを持っています。私は新しいサーバーを起動するときにそれを処理します。サーバーregを使用して、私は自分のGUIから "ゾンビサーバー"を制御し続けます。 :) – motaa