11

Android(2.3.x)でを使用DefaultHttpClientしてThreadSafeClientConnManagerHTTPリクエストをRESTサーバー(埋め込みJetty)に送信しています。

約200秒のアイドル時間の後、サーバーは[FIN]を使用してTCP接続を閉じます。Androidクライアントは[ACK]で応答します。これにより、ソケットは半分閉じた状態のままになります(サーバーはまだリッスンしていますが、データを送信できません)。

クライアントが(を介してHttpClient.execute)その接続を再度使用しようとするとDefaultHttpClient、ハーフクローズ状態を検出し、クライアント側のソケットを閉じて(したがって、[FIN / ACK]を送信してクローズを完了します)、リクエストの新しい接続。しかし、摩擦があります。

代わりに、ハーフクローズされたソケットを介して新しいHTTPリクエストを送信します。送信後にのみ、ハーフクローズ状態が検出され、クライアント側でソケットが閉じられます([FIN]がサーバーに送信されます)。もちろん、サーバーは要求に応答できないため([FIN]はすでに送信されています)、クライアントは要求が失敗したと見なし、新しいソケット/接続を介して自動的に再試行します。

最終的な結果として、サーバーはリクエストの2つのコピーを認識して処理します。

これを修正する方法について何かアイデアはありますか?(私のサーバーは2番目のコピーで正しいことを行いますが、ペイロードが2回送信されることに悩まされています。)

DefaultHttpClientは、最初に新しいHTTPパケットを書き込もうとしたときにソケットが閉じられたことを検出し、そのソケットをすぐに閉じて、新しいソケットを開始するべきではありませんか?サーバーが[FIN]を送信してから数分後に、ソケットで新しいHTTPリクエストがどのように送信されるかについて困惑しています。

4

1 に答える 1

7

これは、JavaでのブロッキングI/Oの一般的な制限です。ソケットからの読み取りを試みる以外に、反対側のエンドポイントが接続を閉じているかどうかを確認する方法はありません。Apache HttpClientは、本質的に非常に短い読み取り操作である非常に古い接続チェックを使用することにより、この問題を回避します。ただし、チェックは無効にできる場合が多く、無効になっていることがよくあります。実際、チェックによって余分な遅延が発生するため、無効にすることをお勧めします。Androidに同梱されているHttpClientのバージョンがこの点でどのように動作するかはわかりませんが、適切な構成パラメーターを使用して、チェックを明示的に有効にしてみることができます。

この問題のより良い解決策は、非アクティブな期間の後、特定の期間(たとえば、150秒)にわたってアイドル状態になっている接続プールから接続を削除することです。

http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d5e652

于 2012-06-28T14:03:13.843 に答える