RMI を介して通信するサーバーとクライアントがあります。彼らの目標は、単純なオブジェクトを共有し、一緒に作業してから、サーバーの切断をシミュレートすることです。
サーバーの名前は rmiregistry にバインドされています。クライアントは rmiregistry を使用して、サーバーへのリモート参照を取得します。次に、この参照を使用して、共有するオブジェクトへの参照を返すメソッドを呼び出します。以降の通信は、この共有オブジェクトを介して行われます。
共有オブジェクトは UnicastRemoteObject であり、サーバーはその実装を所有し、クライアントへの参照を返すメソッドを持っています。
クライアントは共有オブジェクトのインターフェースを認識し、サーバーからリモート参照を取得して、それに対して動作します。サーバーはシリアル化されたコピーではなく、リモート参照を返す必要があることに注意してください。
これは共有オブジェクト インターフェイスです。
public interface CInterface extends Remote {
boolean testMethod() throws RemoteException;
}
そして、これはその実装です
public class CImpl implements CInterface {
@Override
public boolean testMethod() throws RemoteException {
return false;
}
}
これは、クライアントが呼び出したときにリモート参照を返すサーバーのメソッドです。
public CInterface exportRefToC() throws RemoteException {
return new CImpl();
}
クライアントから呼び出すと、この例外が発生します
java.rmi.UnmarshalException: アンマーシャリングでエラーが返されました。ネストされた例外は次のとおりです: java.io.WriteAbortedException: 書き込みが中止されました。java.io.NotSerializableException: サンドボックス.CImpl
このように記述すれば、メソッドを機能させてリモート参照を返すことができます
public CInterface exportRefToC() throws RemoteException {
refToC = new CImpl();
return (CInterface) UnicastRemoteObject.exportObject(refToC, 1099);
}
私が得られないのは、名前を明示的にバインドしていなくても、リモート参照を返すためだけに、レジストリを再度調べる必要がある理由です。クライアントは以前に rmiregistry を使用してサーバーへの参照を取得したため、ブートストラップは完了しています。では、rmiregistry (1099) のポートを知らずに、サーバーがクライアントへの参照を返すことができないのはなぜでしょうか?
おまけの質問ですが、サーバーがクライアントと共有しているオブジェクトを使用不可にしたい場合 (切断をシミュレートするため)、これよりも良い方法はありますか?
UnicastRemoteObject.unexportObject(refToC, true);
編集:共有オブジェクトの実装で UnicastRemoteObject を拡張すると、メソッドの最初のバージョンは機能しますが、アンエクスポートは機能せず、この例外が返されます
java.rmi.ServerException: サーバースレッドで RemoteException が発生しました。ネストされた例外は次のとおりです: java.rmi.NoSuchObjectException: オブジェクトはエクスポートされません
EDIT2: もう一度確認してください。動作します。参照を返す前に保存する必要があります。
public CInterface exportRefToC() throws RemoteException {
refToC = new CImpl();
return refToC;
}