今更ながらの、HttpURLConnection

その使いづらいインターフェイスから、もう二度と出会うことは無いと思っていたHttpURLConnectionですが、(某超大手IT企業の気まぐれのせいで)最近何かと騒がしくなってきました。

ということで、今更ながら、コーディングのサンプルと、その裏で何が起きているか見てみるコンテンツです。

確認は、Debian GNU/Linux 9上で、OpenJDK 8を使用して行っています。それ以外の環境では多少異なるかもしれませんので、注意してください。

特に、Javaのバージョンによる実装の違いはかなり大きいので、必ず対象となるバージョンで十分なテストを行ってください。

GET編

まずは、サンプルソース

必要最低限のことを行う、サンプルソースです。アプリやサーバ内で使用することを想定した作りとなっています。

29行目までが本体で、それ以降はおまけみたいなものです。

タイトルにHttpURLConnectionと銘打っている割に、HttpURLConnectionは出てきません。まあ、世の中そんなもんです。

実際のところ、URLを使用してサーバと通信するだけであれば、HttpURLConnectionの出番はありません。というか、邪魔なだけです。

URLConnectionは、非常に抽象化されたクラスなので、細かい制御がやりづらい代わりに便利な反面もあります。

下記コードのgetメソッドに、ユーザIDとパスワードも含めたftpプロトコルのURL(ftp://[userid]:[passwd]@localhost/wk.txt)を渡せば、該当のファイルが取得できます。

URLConnectionによるGet

6行目と7行目でコネクションタイムアウトとリードタイムアウトを設定しています。特にコネクションタイムアウトはデフォルト設定では非常に長い可能性があるので、設定が必須でしょう。

8行目でキープアライブを無効にしています。

アプリやサーバ内でHTTP通信を行う場合、キープアライブが有効な間、次の接続が出来ないなど、よく問題を起こします。また、実装によっては(JDKのバージョンや環境の違い)キープアライブが有効にならない(連続して同じサーバにリクエストを投げても、一旦切断してからつなぎ直す)こともあるので、無効にすることをお勧めします。

14,15行目で、ブロックしないで読み込める推定のバイト数を取得して、バッファサイズとしています。

詳細は後ほど説明しますが、実は12行目のgetInputStream()から抜けた時点でデータの読み込みは終了しています。そのため、available()が返すのは推定ではなく読み込んだ実際のバイト数となります。

このサンプルでは、読み出し回数を減らすための一例として、バッファサイズをavailable()が返した値+1としていますが、読み込むデータサイズが大きいことが見込まれる場合は、バッファサイズの調整が必要でしょう。

+1としているのは、available()が0を返した場合の対応です。+1をしないでavailable()が0を返した場合、永久ループとなるので注意が必要です。

17行目のread()は、初回の呼び出しで全データをバッファに読み込み、2回めの呼び出しで−1を返して終了となります。

何が起きているかはシーケンスで

下のシーケンスを見るとわかりますが、殆どの処理がgetInputStream()の中で行われます。

サーバとコネクションし、リクエストを投げレスポンスを取得後、サーバからの送信終了(FIN,ACK)を受信した時点でブロックを抜け、アプリケーション側に制御が返ります。

アプリケーションがinputStream.read()を呼び出すと、サーバからの送信終了に対して確認(ACK)を投げ、受信終了(FIN,ACK)を投げブロックを抜けます。

HTTP Get に於ける、ネットワーク上のシーケンス

他の関連ドキュメント

1.今更ながらの、HttpURLConnection Get編

2.今更ながらの、HttpURLConnection Post編

3.今更ながらの、HttpURLConnection 障害処理編

4.今更ながらの、HttpURLConnection (やっと)HttpURLConnectionを使う編