JavaのHttpURLConnectionのdisconnect()メソッドで認識違い(FIN,ACKパケットは流れない)
トレードロボット基本コンポーネントパッケージのWebクラスではWebサイトからhtmlを取得する時の処理の流れを以下のようにしています。
(1)HttpURLConnectionのconnect()を実行
(2)HttpURLConnectionのgetResponseCode()をした上でgetInputStream()からhtmlを取得
(3)HttpURLConnectionのdisconnect()を実行
このそれぞれの処理で以下のようなパケットのやりとりを想定していましたがⅡの方が大きな間違いでした。
Ⅰ.上記(1)のconnect()でSYN→SYN,ACK→ACKのパケットが流れてTCPのコネクションが確立される。
Ⅱ.上記(3)のdisconnect()でFIN,ACKのパケットをやりとりしコネクションを切断する。→×
wireshark(フリーのパケットキャプチャツール)でパケットのやりとりを見てみますとHttpURLConnectionのdisconnect()を行ってもFIN,ACKのパケットは流れません。
FIN,ACKはConnectionヘッダーのデフォルトをKeep-Aliveにしていたためか、(2)を行った後、数秒何もしないとサーバー側から送られてきていました。
Connectionヘッダーをcloseにすると(2)でhtmlを受け取った後、ただちにFIN,ACKパケットがサーバーに送られます。
今までWebクラスのgetHtmlメソッドやpostHtmlメソッドの中が上記の(1)~(3)のような処理でしたが、Keep-Aliveの時に連続してgetHtmlメソッドを実行すると問題が発生しそうです。以前HTTPのレスポンス受信時にIOException"Connection reset"が発生するトラブルがありましたがこれが根本原因なのかもしれません。修正版(getHtmlとpostHtmlメソッドの中のdisconnect()呼び出しをやめる)の基本コンポーネントパッケージを近日中に公開したいと思います。
なお上記以外にも以下のようなことがわかりました。
・Keep-Aliveで接続が持続されている状態でHttpURLConnectionのオブジェクトがスコープを外れるなどして破棄される時にはRST,ACKパケット(強制切断)がサーバーに送られる。
・HttpURLConnectionのconnect()はコネクションが確立していればSYN→SYN,ACK→ACKのパケットが流れない(これはjavadocに書いてありますね)のでKeep-Aliveには対応できる。
| 固定リンク
「システムトレード」カテゴリの記事
- https通信の内容をモニタして解析する(フリーソフトBurpSuiteでキャプチャ)(2009.07.03)
- 初勝利!2012年システムトレード成績(2012.12.29)
- スターアセット証券の商品先物電子取引サービス終了(2009.02.24)
- 2008年度取引ルール(2008.10.22)
- 取引回数とシュミレーション結果の信頼性について考える-2(2009.10.01)
コメント
こんにちは、私も同じ現象が発生して、ここに書かれてる情報で非常に助かりました!ありがとうございます。
結局は、disconnectメソッドの呼び出しをなくしたら、現象が発生しなかったということなんですか?
HttpURLConnectionを破棄した時に、RSTが発生するとありましたが、
これを発生させないような対応ってどうやったらいいんでしょうか?
いきなり質問ばかりですいません。
投稿: オカモト | 2009年11月10日 (火) 13時25分
こんにちは、コメントありがとうございます。
>結局は、disconnectメソッドの呼び出しをなくしたら、現象が発生しなかったということなんですか?
はい、そうです。
> HttpURLConnectionを破棄した時に、RSTが発生するとありましたが、
> これを発生させないような対応ってどうやったらいいんでしょうか?
ConnectionヘッダーをKeep-AliveでなくCloseにするのが一番
手っ取り早いと思いますが、Keep-Aliveの時は最後の通信が
終わった後、しばらく時間をおいてからオブジェクトを破棄する
という手もあると思います。
投稿: | 2009年11月10日 (火) 18時38分
こんにちわ。さっそくのコメントありがとうございます。
すごく参考になりました。
投稿: オカモト | 2009年11月11日 (水) 10時58分
以前にもコメントさせていただきました。
disconnectを使用しない場合、netstatを行うと
CLOSE_WAITが大量発生する問題が発生しました。
FIN,ACKの通信を行われないけども、通信を終了するという意味で
disconectは必要なのかもしれませんね。
定期的に終了することも可能かもしれませんが。。。
ご参考まで。
投稿: オカモト | 2009年11月27日 (金) 12時04分
情報ありがとうございました。
ただ、このCLOSE_WAITの大量発生ですが、当方では発生しません。OSや通信先が関係あるのでしょうか。運用上特に問題が出ていませんし、私の方はこのままにしようと思います。
なおHttpURLConnectionのインスタンスからgetInputStream() して、このストリームからHTTPレスポンスを得ていまして、このストリームは最後にcloseしていますが、このインスタンスのdisconnect() メソッドは使っていないコードになっています。
投稿: | 2009年11月30日 (月) 14時49分
netstatするとCLOSE_WAITが大量発生していることが見える問題ですが、RobotTraderLibraryでも再現しました。通常のhttpリクエスト→htmlのレスポンスという流れでは最後にhttpクライアント側(RobotTraderLibrary)からFIN/ACKをWebサーバに送信していますが、404などのエラーのレスポンスがあった場合はWebサーバからFIN/ACKが送信されてきており、この状態を放置しますとCLOSE_WAITが大量発生します。httpエラーコードが返ってきたらHttpURLConnectionのdisconnect()を呼び出すとhttpクライアント側(RobotTraderLibrary)からFIN/ACKがWebサーバに送り返されCLOSE_WAITの大量発生はなくなりました。RobotTraderLibrary2.33でこの問題に対処しています。
投稿: | 2010年6月15日 (火) 22時10分