web-dev-qa-db-ja.com

HttpsUrlConnectionとキープアライブ

現在のプロジェクトでは、クライアント認証などを扱う_com.Sun.net.httpserver.HttpsServer_を使用しています。現在、クライアントのアドレス/ポートのみが出力されるため、1つのTCP接続が複数のリクエストに使用されているかどうかを確認できます(_keep-alive_)またはすべての要求に対して新しい接続が確立された場合(したがって、新しいSSLハンドシェイクが毎回行われます)。 FireFoxを使用してサーバーに対して複数の要求を行うと、キープアライブが機能していることがわかります。したがって、サーバー部分はGETおよびPOSTリクエストで正常に機能します。

HttpURLConnectionを使用してサーバーに対してリクエストを作成する場合(この場合はno SSLを使用)_keep-alive_も機能します:複数の順次開始されたリクエストに対して1つの接続のみが確立されます。

しかし、HttpsURLConnection(まったく同じコードを使用しますが、sing SSL)を使用すると、_keep-alive_は機能しなくなります。そのため、同じSSLContext(およびSSLSocketFactory)を使用していますが、リクエストごとに新しい接続が確立されます。

_// URL myUrl = ...
// SSLContext mySsl = ...
HttpsURLConnection conn = (HttpsURLConnection) myUrl.openConnection();
conn.setUseCaches(false);
conn.setSSLSocketFactory(mySsl.getSocketFactory());

conn.setRequestMethod("POST");
// send Data
// receive Data
_

HttpsURLConnectionが_keep-alive_を使用するように強制するにはどうすればよいですか?多くのリクエストが実際のパフォーマンスの問題である多くのSSLハンドシェイクにつながるためですか?

更新(2012-04-02):毎回mySsl.getSocketFactory()を呼び出す代わりに、SSLSocketFactoryをキャッシュしようとしました。しかし、何も変わっていません。問題はまだ存在します。

25
Biggie

HttpsUrlConnectionで動作させることができませんでした。しかし、ApacheのHTTPクライアントは、SSL接続でのキープアライブを非常にうまく処理します。

5
Biggie

私はこのまったく同じ問題に遭遇し、いくつかの詳細なデバッグの後に最終的に解決策を見つけました。

Http(s)UrlConnectionはデフォルトでKeep-Aliveを処理しますが、ソケットを再利用するには非常に特殊な状態にする必要があります。

これらは:

  • 入力ストリームは完全に消費される必要があります。入力ストリームで-1が返されるまでreadを呼び出して、閉じる必要があります。
  • 基礎となるソケットの設定では、まったく同じオブジェクトを使用する必要があります。
  • Http(s)URLConnectionの処理が終了したら、disconnect(はい、これは直感に反します)を呼び出す必要があります。

上記のコードでは、問題は次のとおりです。

conn.setSSLSocketFactory(mySsl.getSocketFactory());

初期化中にgetSocketFactory()の結果を静的変数に保存し、それをconn.setSSLSocketFactoryに渡すことで、ソケットを再利用できます。

17
Bill Healey

SSL接続の確立は、サービスの呼び出しまたはブラウザーから多くのリソースを取得する場合に非常に高価です。

Java Http(s)UrlConnectionはHTTP(S)を処理します デフォルトでキープアライブ

デフォルトSSLSocketFactory のソースコードが見つかりませんでした。おそらく、キープアライブメカニズムが実装されています。確認として、テスト用に独自のSSLSocketFactory実装を無効にし、javax.net.ssl.trustStore自己署名証明書が受け入れられるようにします。

OpenJDK 7によれば ServerImpl を使用する実装 ServerConfig 使用したHttpsServerは、デフォルトで5分のタイムアウトのキープアライブを発行します。

プロパティの設定Sun.net.httpserver.debugからtrueサーバー側に移動して詳細を取得します。

コードがヘッダーを追加しないように注意してくださいConnection: closeキープアライブメカニズムを無効にします。

2
Yves Martin

Apache Webサーバーをセットアップし、次のディレクティブを追加して、Apacheのaccess.logにhttpクライアントのキープアライブ接続があるかどうかを確認します。

LogFormat "%k %v %h %l %u %t \"%r\" %>s %b" common
CustomLog "logs/access.log" common 

http://httpd.Apache.org/docs/current/mod/mod_log_config.html

"%k"この接続で処理されたキープアライブ要求の数。 KeepAliveが使用されている場合、たとえば、「1」は最初のキープアライブリクエストを意味し、「2」は2番目などを意味します。それ以外の場合、これは常に0(最初の要求を示す)です。

0
WENPIN

次のコードを追加してみてください。

con.setRequestProperty("Connection", "Keep-Alive");
con.setRequestProperty("Keep-Alive", "header");
0
UVM

私が理解できる限り、 HTTP/1.1 および [〜#〜] https [〜#〜] プロトコル、文書化されています hereKeep-Aliveend-to-endヘッダーではなく、hop-to-hopヘッダー。 SSLには、新しい接続ごとに「異なるホップ」(CAとサーバーなど)間で複数のステップのハンドシェークが含まれるため、Keep-AliveはSSLコンテキストでは適用されない場合があります。したがって、- それが理由である可能性がありますKeep-AliveヘッダーはHTTPS接続を使用して無視されます。これに基づいて この質問 を確認する必要があるかもしれませんoneHTTP接続のインスタンスがKeep-Alive観察。また、質問では、Apache HTTPClientがより良い解決策であるようです。

0
nobeh

私は同じ問題に直面しました、そしてビル・ヒーリーは正しいです。以下のサンプルコードをいくつかのhttpsライブラリでテストしました。 HttpsURLConnectionとOKHTTPはまったく同じ動作です。ボレーはセッション再開時に少し異なりますが、動作はほぼ同じです。これが助けになることを願っています。

public class SampleActivity extends Activity implements OnClickListener {

    // Keep default context and factory
    private SSLContext mDefaultSslContext;
    private SSLSocketFactory mDefaultSslFactory;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        findViewById(R.id.button_id).setOnClickListener(this);

        try {
            // Initialize context and factory
            mDefaultSslContext = SSLContext.getInstance("TLS");
            mDefaultSslContext.init(null, null, null);
            mDefaultSslFactory = mDefaultSslContext.getSocketFactory();
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            Log.e(TAG, e.getMessage(), e);
        }

    }

    @Override
    public void onClick(View v){
        SSLContext sslcontext;
        SSLSocketFactory sslfactory;

        try {
            // If using this factory, enable Keep-Alive
            sslfactory = mDefaultSslFactory;

            // If using this factory, enable session resumption (abbreviated handshake)
            sslfactory = mDefaultSslContext.getSocketFactory();

            // If using this factory, enable full handshake each time
            sslcontext = SSLContext.getInstance("TLS");
            sslcontext.init(null, null, null);
            sslfactory = sslcontext.getSocketFactory();
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            Log.e(TAG, e.getMessage(), e);
        }

        URL url = new URL("https://example.com");
        HttpsURLConnection = conn = (HttpsURLConnection) url.openConnection();
        conn.setSSLSocketFactory(sslfactory);
        conn.connect();
    }
}

更新:

SSLSocketFactoryを共有すると、キープアライブが有効になります。 SSLContextを共有して各リクエストを取得すると、セッションの再開が可能になります。 TLSスタックの仕組みはわかりませんが、一部のモバイルデバイスでのこれらの接続動作を確認しただけです。

複数のクラス間でキープアライブを有効にする場合は、シングルトンパターンを使用してSSLSocketFactoryのインスタンスを共有する必要があります。

セッションの再開を有効にする場合は、SSLSessionCacheTimeout(Apache)、ssl_session_timeout(nginx)。

0
forte916