1

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;
    }
    .
    .
    .
}
4

1 に答える 1

0
public class MySocketFactorySettingKeepAlive ... {
  // overwrite createSocket methods, call super.createSocket, add keepAlive
}

Socket.setSocketImplFactory(youFactoryDemandingKeepAlive);

そして、RMIを使用してください。

私の記憶が正しければ、秘訣は、システムが最初のソケットを開く前にファクトリを設定することです.Javaはファクトリを上書きすることを許可していません。最悪の場合、リフレクションを使用して上書きします :))) (冗談です; ハックになるでしょう)

また、SecurityManager で特定の操作を許可する必要がある場合もあります。

于 2008-10-22T23:47:42.947 に答える