Java RMIがリースの期限切れ後にソケットを閉じない
質問
RMI対応アプリケーションがソケットをリークしているようです。 RMI経由でサービスを提供するJavaアプリケーションがあります。 Linux上で実行されるJava SE 1.6 RMI実装を使用しています。私が観察している問題は、クライアントがレジストリを使用してリモートオブジェクトへの参照を取得し、接続が突然切断された場合(電力損失、ケーブルの取り外しなど)、サーバーがソケットを開いたままにすることです。クライアントのリースが期限切れになった後、RMI実装がクリーンアップすることを期待しますが、それは起きていません。サーバーでは、リースの期限が切れるとリモートオブジェクトの unreferenced()
メソッドが呼び出されますが、ソケットは「ESTABLISHED」のnetstatに表示されたままです。無期限に。
クライアントに特定の動作を強制することはできないため、数日後、Linuxディストリビューションでデフォルトの制限である1024に達し、ファイル記述子が開かれ、サーバーが新しいソケットを開けなくなったり、ファイル。 TCPキープアライブについて考えましたが、RMIはネットワーク層を抽象化しているため、接続が確立された後は実際のサーバーソケットにアクセスできません。
リースが期限切れのクライアント接続に関連付けられたソケットをRMIレイヤーに強制的にクリーンアップさせる方法はありますか?
更新:使用したソリューションは、選択した回答に似ていますが、異なるアプローチを使用しています。カスタムソケットファクトリを使用し、createServerSocket()によって返されたServerSocketインスタンスを、accept()を除くすべてのメソッドを通過させる透明なラッパーにラップしました。 accpetメソッドでは、ソケットが返される前にキープアライブが有効になります。
public class KeepaliveSocketWrapper extends ServerSocket
{
private ServerSocket _delegate = null;
public KeepaliveSocketWrapper(ServerSocket delegate)
{
this._delegate = delegate;
}
public Socket accept() throws IOException
{
Socket s = _delegate.accept();
s.setKeepAlive(true);
return s;
}
.
.
.
}
解決
public class MySocketFactorySettingKeepAlive ... {
// overwrite createSocket methods, call super.createSocket, add keepAlive
}
Socket.setSocketImplFactory(youFactoryDemandingKeepAlive);
次に、RMIを使用します。
私が正しいことを覚えているなら、トリックはシステムが最初のソケットを開く前にファクトリを設定することです-Javaはファクトリの上書きを許可しません。最悪の場合、リフレクションを使用して上書きします:)))(冗談です。ハックになります)
また、SecurityManagerで特定の操作を許可する必要がある場合があります。