RMI 対応アプリケーションがソケットをリークしているようです。RMI 経由でサービスを提供する Java アプリケーションがあります。Linux で動作する Java SE 1.6 RMI 実装を使用しています。私が観察している問題は、クライアントがレジストリを使用してリモート オブジェクトへの参照を取得した後、接続が突然切断された場合 (停電、ケーブルが抜かれているなど)、サーバーがソケットを開いたままにすることです。クライアントのリース期限が切れた後、RMI 実装がクリーンアップされることを期待していますが、そうはなっていません。unreferenced()
サーバーでは、リースの有効期限が切れるとリモート オブジェクトのメソッドが呼び出されますが、ソケットは netstat で "ESTABLISHED" 状態で無期限に表示されたままになります。
クライアントに特定の動作を強制することはできないため、数日後、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;
}
.
.
.
}