第 5 章 通信の制御
5.1 クライアント/サーバープログラミング
多くのプログラムは、クライアントとサーバーが対になって動作します。iアプリサービスでは、
サーバーはインターネット経由でアクセスするリモートホストシステムであり、クライアントは携 帯電話上で動作する Java アプリケーションです。クライアントとサーバーは、通常、IP アドレス
(サーバー固有の識別子)とポート番号(接続を特定のプロセスにルーティングするための識別子)
を知ることによって相互に通信します。構造をシンプルにするため、ネットワーク接続には CLDC 仕様で定義されている入出力ストリームが使用されます。データの読み書きは、一般的な Java の ストリームクラスおよびメソッドを使って行います。そのため、通信対象への接続から入力ストリ ームを取得するメソッドと出力ストリームを取得するメソッドがそれぞれ用意されています。これ によって、クライアントとサーバーは相互に通信することができます。クライアントは、HTTP サ ーバーから Web ページの内容を入手するなどのインターネットサービスが必要になると、URL を 使ってこのサービスにアクセスします。iアプリ実行環境では、J2SE における
HttpURLConnection のサブセットとして HttpConnection インタフェースが提供されます。
次のコードは、HttpConnection インタフェース(の実装オブジェクト)の設定と使用の例を示 したものです。
例: 接続の確立と動作
package spaceinv;import java.io.*;
import javax.microedition.io.*;
import com.nttdocomo.io.*;
private String[] getScoreList(int score) { try {
// HTTP接続(HttpConnection)オブジェクトを取得する。
HttpConnection conn = (HttpConnection)Connector.open(
"http://backflip.sfbay:8080/scores",Connector.READ_WRITE, true);
// リクエストメソッドとコンテンツタイプを設定する。
conn.setRequestMethod(HttpConnection.POST);
conn.setRequestProperty("Content-Type","text/plain");
// 出力ストリームを取り出す。
OutputStream out = conn.openOutputStream();
// データを書き込む(実際の接続がまだ確立されていないため、
// 書き込まれたデータは一時的にバッファに入れられる)。
out.write("Highscore-Game: Space Invaders¥n".getBytes());
out.write(("Highscore-Name: " + SpaceInvaders.USER.getName() +
"¥n").getBytes());
out.write(("Highscore-Value: " + score + "¥n").getBytes());
// 出力ストリームをクローズする。
out.close();
// リモート資源に実際に接続する。
conn.connect();
String[] result = new String[HighScoreScreen.MAX_ENTRIES];
// 入力ストリームを取り出す。
InputStream in = conn.openInputStream();
if (in == null)
throw new IOException("high score servlet unreachable");
Copyright Ⓒ 2008-2012 NTT DOCOMO, Inc. All Rights Reserved.
// データを読み取る。
for (int i=0; i<HighScoreScreen.MAX_ENTRIES; i++) {
result[i] = readLine(in);
}
// 入力ストリームをクローズする。
in.close();
// HTTP接続をクローズする。
conn.close();
return result;
} catch (Exception x) {
return new String[] {"Scores", "currently", "unavailable."};
}
}
HttpConnection は、 HTTP や HTTPS プロトコルのネットワーク資源にアクセスするために使用 されるインタフェースです。このインタフェースを実装したクラスのインスタンスは、URL で指 定する資源の読み取りと書き込みの両方に使用できます。一般に、URL との接続は、次の手順に 従って行います。
1. Connector.open()メソッドを呼び出して接続オブジェクトを作成する。オープンモードとリクエス トメソッドは以下のように対応する。
Connector.READ : GETメソッドに対応 Connector.READ_WRITE: POSTメソッドに対応
2. セットアップパラメータを設定する(リクエストメソッドとリクエストヘッダ)。アプリケーションプ ログラムから設定可能なリクエストヘッダは、If-Modified-SinceとContent-Typeの2つです。
3. HttpConnection.openOutputStream()メソッドを呼び出して、この接続の出力ストリームを取得 する。
4. OutputStream.write()メソッドを使って出力ストリームに書き込む。
5. OutputStream.close()メソッドを使って出力ストリームをクローズする。
6. HttpConnection.connect()メソッドを使ってリモートオブジェクトに実際に接続する。この後、
必要に応じてレスポンスヘッダを参照することができます。アプリケーションプログラムから参照可能 なレスポンスヘッダについては、APIリファレンス(HttpConnection.getHeaderField()メソッ ド)を参照してください。
7. HttpConnection.openInputStream()メソッドを使って入力ストリームを取得する。
8. InputStream.read()メソッドを使って入力ストリームから読み取る。
9. InputStream.close()メソッドを使って入力ストリームをクローズする。
10. HttpConnection.close()メソッドを使って接続をクローズする。
上記の 3~5 は、 POST メソッド使用時における HTTP リクエストボディの書き込み処理に相当しま
す。また 7~9 は、 POST、 GET 両メソッドにおける HTTP レスポンスボディの読み込み処理に相当
します。
これらの処理はそれぞれ必須ではなく必要に応じて行うものですが、処理を行う場合は全体として 上記のシーケンスに合致するようにしてください。例えば HttpConnection.connect()を呼び 出した後で HttpConnection.openOutputStream()を呼び出すと、機種によっては例外が発生 することがあります。
次の図に、接続の始めから終わりまでの状態遷移を示します。
Copyright Ⓒ 2008-2012 NTT DOCOMO, Inc. All Rights Reserved.
HttpConnection の状態遷移図
Connector.open()
オープン
接続済み
クローズ
書き込み可能
読み取り可能 読み取り完了
書き込み完了 初期化
HttpConnection.openOutputStream()
HttpConnection.connect()
HttpConnection.openInputStream()
HttpConnection.close()
OutputStream.write()
InputStream.read()
OutputStream.close()
InputStream.close()
凡例
状態 状態遷移
図8: HttpConnectionの状態遷移
注意事項:
● HttpConnectionに渡すURLには、次の制約があります。
• IPアドレスはシンボリックでなければなりません("www.nttdocomo.co.jp"など)。HttpConnection では、数値IPアドレス("127.0.0.1"など)は使用できません。
• HttpConnectionに渡すURLのプロトコル、ホスト名、ポートは、iアプリのダウンロード元とな ったURL(ADFのPackageURLキーでの指定)と同じでなければなりません。
● 1つのiアプリから同時に接続可能なHttpConnectionの数は1つだけです。
● iアプリサービスにおけるクライアント/サーバーシステムでは、クライアント(携帯電話)とサーバー(Web サーバー)の間にiモードサーバーが介在しています。iモードサーバーでは、以下のような異常検出時に レスポンスステータスを200としてメッセージを返すことがあります。このような場合、クライアント側で はレスポンスステータスに基づいた正常性確認を行うことができません。クライアント側で厳密な正常性確 認を行うには、独自のHTTPレスポンスヘッダの付加やHTTPレスポンスボディの内容による判断を行うよ うにしてください。
• iモードサーバーのインターネット向けプロキシサーバー輻輳時
• 公式メニューサイトのメンテナンス時(公式メニューサイトのコンテンツプロバイダより申請のあっ た場合)
なお、異常を示すレスポンスステータスが返却された場合、iアプリ実行環境は例外をスローします。
● HTTPリクエスト/レスポンスボディについてx-www-form-urlencoded形式のエンコード、デコードを行うには、
それぞれ以下のユーティリティクラスを使用してください。
• com.nttdocomo.net.URLEncoder
• com.nttdocomo.net.URLDecoder
● HTTP(S)通信で送信可能なリクエストボディのサイズ、および受信可能なレスポンスボディのサイズには、
プロファイルの世代により以下の制限があります。
Copyright Ⓒ 2008-2012 NTT DOCOMO, Inc. All Rights Reserved.
この制限は、アプリケーションプログラムが直接HttpConnectionを操作する場合だけでなく、メディア データをHTTP通信を介して取得する際にも適用されます。
● iアプリがアクセスするURLには、サーバー側で基本認証(BASIC認証)の設定が行われている場合があ ります。このようなURLにアクセスした場合、携帯電話は自動的にユーザーIDとパスワードの入力を促す ダイアログを表示します。アプリケーションプログラムが独自の処理で基本認証の情報(Authorization リクエストヘッダなど)をサーバーに送信することはできません。
● iアプリが通信を行っている最中に通話着信があった場合、iアプリはサスペンドします。通話終了後、i アプリに復帰し例外がスローされます。
● WebサーバーにPOSTメソッドでHTTPリクエストを送信する場合、HTTPリクエストボディの設定内容に 適したコンテンツタイプを指定するようにしてください。コンテンツタイプ(Content-Typeヘッダ)の設 定にはHttpConnection.setRequestProperty()メソッドを使用します。また、リクエストボディに書 き込むデータが存在しない場合、POSTメソッドではなくGETメソッドを使用します。GETメソッド使用時 はコンテンツタイプの設定は行わないようにしてください。
● iモードサービスでは、Webサーバーからのレスポンスにはコンテンツ長(Content-Lengthヘッダ)の 設定を必須としています。iアプリからのHTTP(S)通信においても、Webサーバーからのレスポンスにはコ ンテンツ長の設定を行うようにしてください。
● iアプリが通信を行っている状態でiアプリの中断(3.6項参照)が発生すると、通信は中断されます。この 場合、iアプリの実行が再開された時点で例外が発生します。
● HttpConnectionインタフェースには、HTTPレスポンスに含まれるレスポンスヘッダの内容を参照するた めのgetHeaderField()メソッドがあります。このメソッドでは”x-“で始まるユーザ定義ヘッダも取得す ることができますが、iモードにおいてはiモードサーバーが携帯電話との通信を制御するために独自のユ ーザ定義ヘッダを使用する場合があるため、iアプリではユーザ定義ヘッダは使わないことを強く推奨しま す。iモードサーバーが使用しているものと同名のヘッダがiアプリのHTTP通信で使用された場合、iモ ードサーバーはそのヘッダを削除する場合があります。
【DoJa-2.0】
・ DoJa-2.0プロファイル以降に対応した携帯電話では、外部との通信機能を一切停止して、通信を使用し
ない機能のみ利用可能とするセルフモード機能が搭載されます。ユーザーが携帯電話をセルフモードに している状態では、iアプリの起動を行うことはできますが起動されたiアプリがHTTP(S)通信を行う ことはできません。
・ DoJa-2.0プロファイル以降では、HTTP(S)通信で指定するURLの長さとして、スキーム/パス部に255バ
イト、クエリー部に512バイトまで指定することができます。
・ DoJa-1.0プロファイルでは、HTTPレスポンスのステータスコードについて以下のように定義されていま
す。
- HttpConnection.HTTP_SERVER_ERROR(500)
- HttpConnection.HTTP_INTERNAL_ERROR(501)
これに対し、DoJa-2.0プロファイル以降では
- HttpConnection.HTTP_INTERNAL_ERROR(500)
- HttpConnection.HTTP_NOT_IMPLEMENTED(501)
プロファイル リクエスト レスポンス
DoJa-1.x 80Kバイト 100Kバイト
DoJa-2.x 80Kバイト 150Kバイト
DoJa-3.x 80Kバイト 150Kバイト
DoJa-4.x / 5.x 80Kバイト 150Kバイト