0

Java アプリケーションと HttpsURLConnection 実装を介して Web サービスに接続しています。接続を開き、try with resource ブロックを使用して入力ストリームと入力ストリーム リーダーを開き (終了したら閉じます)、finally ブロックで connection.disconnect を呼び出します。コードは以下にあり、ほとんどの場合動作します。

    HttpsURLConnection connection = null;
    try{       
         // basic authentication
        String encodedAuthString =
            DatatypeConverter.printBase64Binary((userName + ":" + password)
                .getBytes());   

        connection = (HttpsURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setRequestProperty("Authorization", "Basic " + encodedAuthString);

        //try-with-resource to close connections when complete
        try(InputStream in = connection.getInputStream();
            InputStreamReader isr = new InputStreamReader(in)){
            int numCharsRead;
            char[] charArray = new char[1024];
            StringBuffer sb = new StringBuffer();
            while ((numCharsRead = isr.read(charArray)) > 0) {
                sb.append(charArray, 0, numCharsRead);
            }

            jsonResult = sb.toString();
        }

    } 
    catch (Exception e){
        throw e;
    } finally {
        if(connection!= null)
            connection.disconnect();
    }

ただし、このコードは複数のスレッドによって 1 秒間に数回呼び出される可能性があります (ただし、実際に含まれているメソッドは同期されているため、一度に 1 つのスレッドしか接続にアクセスできません)。ネットワーク担当者と協力して作業を行ったところ、アプリケーションが「connection.disconnect()」を呼び出しても、サーバー上で接続がすぐに切断されないことがわかりました。サーバー ログに切断の呼び出しが表示されますが、サーバーが完全に切断される前に Java アプリケーションが再接続を試み、「接続拒否エラー」が発生します。

再度接続する前にJava経由で完全に切断するか、切断が呼び出されたときにサーバー設定を介して強制的に切断する方法はありますか? または、エラーの可能性を減らすために、より速く実行する方法はありますか? 接続が成功するまで接続を再試行できますが、それはハックのようです。

誰かが私を正しい方向に向けるのを手伝ってくれますか?

更新 - 2013年 1 月 6日 - 調査を続けたところ、tcpdump を読んで、クライアントが 100 回のリクエストで同じポートに接続していて、101 回目のリクエストでポートが変更され、エラーが発生することがわかりました。接続は最終的に回復し、新しいポートでリクエストの送受信を開始しますが、回復するまでに最大 1 分かかる場合があります。以下にtcpdumpを含めました。クライアントが新しいポートで送信すると、宛先 IP が新しいポートで「R」eset を返すことがわかります。このため、エラーは宛先でのエラーの結果であり、クライアントからではないと考えていますが、このレベルでの理解が限られているため、まだ検証しようとしています.

13:20:25.925760 IP DESTINATION_IP.https > CLIENT_IP.53321: P 197809:197846...
13:20:25.925819 IP CLIENT_IP.53321 > DESTINATION_IP.https: . ack 197846 wi...
13:20:25.926393 IP CLIENT_IP.53321 > DESTINATION_IP.https: P 82874:82911(3...
13:20:25.926424 IP CLIENT_IP.53321 > DESTINATION_IP.https: F 82911:82911(0...
13:20:25.928629 IP CLIENT_IP.53322 > DESTINATION_IP.https: S 702514925:702...
13:20:26.005902 IP DESTINATION_IP.https > CLIENT_IP.53321: . ack 82911 win...
13:20:26.008461 IP DESTINATION_IP.https > CLIENT_IP.53322: R 0:0(0) ack 70...
13:20:26.011274 IP DESTINATION_IP.https > CLIENT_IP.53321: P 197846:197883...
13:20:26.011290 IP CLIENT_IP.53321 > DESTINATION_IP.https: R 494623963:494...
13:20:26.011300 IP DESTINATION_IP.https > CLIENT_IP.53321: F 197883:197883...
13:20:26.011305 IP CLIENT_IP.53321 > DESTINATION_IP.https: R 494623963:494...
4

2 に答える 2

0

disconnect() 呼び出しを取り除きます。これにより、HTTP キープアライブが機能しなくなります。したがって、より多くの TCP 接続を使用しているため、サーバーのバックログ キューがいっぱいになり、(一部のプラットフォームでは) 接続拒否が発生します。ほとんどの場合、入力ストリームを閉じるだけで十分です。

于 2014-01-05T22:06:28.047 に答える
-1

HTTP キープアライブにより、接続は維持されます。

これはサーバーによって大雑把に無効にされ、HTTP クライアント ライブラリがいつデータの送信を終了したかを判断できなくなります。つまり、Content-Length ヘッダーを送信せず、チャンク エンコーディングも使用しません。ただし、多くの Web フレームワークはどちらか一方を自動的に実行します。クライアント アプリケーションは、サーバーがデータの送信を終了したときを判断する必要があり、Content-Length やチャンク エンコーディングなどに依存する可能性があるため、いずれにせよアプリケーションはそれらに依存する可能性があります。これを決定するために!

ただし、接続拒否エラーがこの現象に関連している可能性は低いです。実際、HTTP キープアライブは、既存の接続を再利用するため、接続拒否エラーが表示される可能性を低くする必要があります。

于 2013-12-19T22:40:57.243 に答える