httpurlconnectionの実装
-
27-09-2019 - |
質問
httpurlconnectionは永続的な接続をサポートしているため、複数のリクエストに接続を再利用できるようにしました。私はそれを試しましたが、2番目の投稿を送信する唯一の方法は、OpenConnectionをもう一度呼び出すことでした。それ以外の場合は、IllegalStateException( "既に接続されている")を取得しました。以下を使用しました。
try{
URL url = new URL("http://someconection.com");
}
catch(Exception e){}
HttpURLConnection con = (HttpURLConnection) url.openConnection();
//set output, input etc
//send POST
//Receive response
//Read whole response
//close input stream
con.disconnect();//have also tested commenting this out
con = (HttpURLConnection) url.openConnection();
//Send new POST
2番目のリクエストは同じTCP接続(Wiresharkで確認された)で送信されますが、Disconnectと呼ばれているので(これが私が望むものですが)理由がわかりません。 httpurlconnectionのソースコードを確認しましたが、実装は同じ宛先への接続のキープライブキャッシュを保持します。私の問題は、最初のリクエストを送信した後、接続がキャッシュにどのように戻されるかがわからないことです。切断は接続を閉じ、切断なしでは、接続がどのようにキャッシュに戻されるかがわかりません。キャッシュには、すべてのアイドル接続を通過する実行方法があることがわかりました(どのように呼び出されるかわかりません)が、接続がどのようにキャッシュに戻されるかはわかりません。発生しているように見える唯一の場所は、httpclientの完成した方法ですが、これは応答のある投稿の場合は呼び出されません。誰かがこれについて私を助けることができますか?
編集私の興味は、TCP接続の再利用のためのHTTPURLCONNECTIONオブジェクトの適切な取り扱いは何ですか。入力/出力ストリームを閉じた後、url.openconnection()が続きます。新しいリクエストを送信するたびに(disconnect()を回避)?はいの場合、最初のリクエストのために接続がキャッシュから削除され、それがどのように返されるかを見つけることができないため、url.openconnection()を2度目に呼び出すと、接続がどのように再利用されているかがわかりません。接続がKeepAliveキャッシュ(バグ?)に戻されない可能性はありますが、OSはまだTCP接続をリリースしておらず、新しい接続では、OSはバッファー接続(まだリリースされていません)などを返しますか?編集2私が見つけた唯一の関連は出身でした jdk_keepalive
... urlconnection.getInputStream()によって返された入力ストリームでアプリケーションがclose()を呼び出すと、JDKのHTTPプロトコルハンドラーは接続をクリーンアップしようとし、成功した場合は、将来のHTTPリクエストによる再利用の接続キャッシュに接続を入れます。
しかし、これがどのハンドラーであるかはわかりません。 sun.net.www.protocol.http.handlerは、私が感謝したようにキャッシュをしません!
解決
入力/出力ストリームを閉じた後、url.openconnection()が続きます。新しいリクエストを送信するたびに(disconnect()を回避)?
はい。
はいの場合、最初のリクエストのために接続がキャッシュから削除され、それがどのように返されるかを見つけることができないため、url.openconnection()を2度目に呼び出すと、接続がどのように再利用されているかがわかりません。
あなたは混乱しています HttpURLConnection
根底にある Socket
と これは 基礎となるTCP接続。彼らは同じではありません。 HttpURLConnection
インスタンスはgc'd、根底にあります Socket
あなたが電話しない限り、プールされます disconnect().
他のヒント
httpurlconnectionのJavadocから(私の強調):
各httpurlconnectionインスタンスは、aを作成するために使用されます 単一の要求ですが、HTTPサーバーへの基礎となるネットワーク接続は、他のインスタンスによって透過的に共有される場合があります。 httpurlconnectionのinputstreamまたはoutputStreamでclose()メソッドを呼び出して、リクエストがこのインスタンスに関連付けられた無料のネットワークリソースを無料で使用できますが、共有された永続的な接続には影響しません。 disconnect()メソッドを呼び出します 五月 その時点で永続的な接続がアイドル状態である場合、基礎となるソケットを閉じます。
入力ストリームが閉じていると、接続が実際にキャッシュされていることがわかりました。入力ストリームが閉じられると、基礎となる接続が緩衝されます。ただし、オブジェクトはまだ「接続」されていると見なされるため、HTTPURLCONNECTIONオブジェクトはさらにリクエストに使用できません。つまり、そのブール接続はTRUEに設定されており、接続がバッファに戻されてもクリアされません。したがって、新しい投稿のために新しいHTTPURLCONNECTIONをインスタンス化するたびにインスタンス化する必要がありますが、タイミングが出ていない場合は、基礎となるTCP接続が再利用されます。したがって、EJP Answerは正しい説明でした。私が見た動作かもしれません(TCP接続の再利用)disconnect()を明示的に呼び出していたにもかかわらず、OSによってキャッシュが行われたためですか?私は知らない。知っている人が説明できることを願っています。ありがとう。
JDKのHTTPURLCONNECTIONを使用して、どのように「HTTP1.0の使用を強制的に使用しますか」?
セクションによると Java 1.5ガイドの「永続的な接続」 http1.1接続のサポートは、Javaプロパティをオフにしたり、使用したりできます http.keepAlive
(デフォルトはtrue)。さらに、Javaプロパティ http.maxConnections
宛先あたりの(同時)接続の最大数を、いつでも生存するために保持されることを示します。
したがって、Javaプロパティを設定することにより、「HTTP1.0の力使用」を一度にアプリケーション全体に適用できます。 http.keepAlive
偽り。
うーん。私はここで何かを見逃しているかもしれません(これは古い質問だから)が、私が知る限り、基礎となるTCP接続を強制するための2つのよく知られている方法があります。
- HTTP 1.0の強制使用(1.1は永続的な接続を導入しました) - これはHTTPリクエスト行で示されています
- value 'close'を持つ「接続」ヘッダーを送信します。これも閉鎖を強制します。
ストリームを放棄すると、アイドルTCP接続が発生します。応答ストリームは完全に読み取る必要があります。私が最初に見落としていたもう一つのことは、このトピックに関するほとんどの答えで見落とされているのを見たことがあります。例外の場合にエラーストリームに対処することを忘れることです。これに類似したコードリソースを適切にリリースしていなかった私のアプリの1つを修正しました。
HttpURLConnection connection = (HttpURLConnection)new URL(uri).openConnection();
InputStream stream = null;
BufferedReader reader = null;
try {
stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream, Charset.forName("UTF-8")));
// do work on part of the input stream
} catch (IOException e) {
// read the error stream
InputStream es = connection.getErrorStream();
if (es != null) {
BufferedReader esReader = null;
esReader = new BufferedReader(new InputStreamReader(es, Charset.forName("UTF-8")));
while (esReader.ready() && esReader.readLine() != null) {
}
if (esReader != null)
esReader.close();
}
// do something with the IOException
} finally {
// finish reading the input stream if it was not read completely in the try block, then close
if (reader != null) {
while (reader.readLine() != null) {
}
reader.close();
}
// Not sure if this is necessary, closing the buffered reader may close the input stream?
if (stream != null) {
stream.close();
}
// disconnect
if (connection != null) {
connection.disconnect();
}
}
バッファリングされた読者は厳密に必要ではありません。私のユースケースが一度に1行ずつ読む必要があるため、私はそれを選びました。
参照: http://docs.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html