UnityでHTTPリクエストの処理を実装する機会があると思います。HTTPリクエストする際、地味に忘れては行けないのが、タイムアウト処理です。
この処理がないと、永遠にサーバーからのレスポンスを待ち続けることになり、ゲームが全く進行しないという大きな不具合につながるからです。
この記事では、前半にタイムアウトが必要な理由の解説、後半で、HTTPリクエストの実装方法を解説します。
タイムアウトが必要な理由
何らかの理由でサーバーから全くレスポンスがないとき、タイムアウトがないと永遠に待ち状態になってしまう。その結果、ユーザーがイライラすることになります。
実際に起きたできごと
ゲームアプリを開発していた時の話です。
ゲーム内に戦闘シーン(FFに近いイメージ)があります。戦闘が終わると、戦闘結果をサーバーに送信する仕組みです。戦闘結果がサーバに反映されない限り、先に進めないようになっていました。
あるとき、何らかの理由でサーバーから20分経ってもレスポンスがないときがありました。その結果、ゲームの進行が止まり、ユーザーから「30分以上かかってようやくクリアできたのに、フリーズしてしまい先に進めないよ!おかげで、クリアした状態が保存されていないよ!どうしてくれるの!!」というお怒りを頂きました。
話がそれますが、PSでよくCDの読み込みに失敗してゲームがフリーズすることがよくありました。フリーズが起きるとこれまで遊んでいたデータが無くなってしまいます。1時間以上の努力が水の泡でした。そのときは、怒り爆発していました。
そのように考えると、ユーザーの怒りも相当なものかもしれません。
ユーザーからの指摘があってから、タイムアウトの処理が必要と思うようになりました。
リクエストから一定の時間を過ぎたら、タイムアウトしリトライ、もしくはエラーを出力するなどすればよいでしょう。
タイムアウトの実装例
UnityWebRequestを使ってタイムアウトを実装してみます。
PHP側は、タイムアウトが発生するかどうかを試すため、10秒ほどプロセスをsleepさせます。
■Unity側のソースコード
//UnityWebRequestでhttpリクエストを実装する
//UnityWebRequestには、タイムアウト処理が実装されており
//UnityWebRequestのメンバー変数timeoutに整数を設定するだけです
IEnumerator UnityWebRequestDownload(string url) {
UnityWebRequest www = UnityWebRequest.Get(url);
//タイムアウトを3秒に設定する
www.timeout = 3;
Debug.Log("インターネット接続前:" + System.DateTime.Now.ToString());
//リクエスト開始
yield return www.Send();
Debug.Log(www.error + " " + System.DateTime.Now.ToString());
Debug.Log(www.downloadHandler.text + " " + System.DateTime.Now.ToString());
}
■PHP側のソースコード
//sleep関数
sleep(10);
echo "sample ok";
上記の実装の結果、たしかにタイムアウトが発生することを確認できます。
補足
HTTPリクエストの処理は、以下のように「WWW」でもリクエスト処理を数行で実装できますが、タイムアウト処理の実装を独自に実装うする必要があり面倒です。タイムアウトが必要な場合は、UnityWebRequestを使うことをおすすめします。
//WWWでhttpリクエスを実装する
//WWWには、タイムアウト処理がないため独自に作る必要がある。
IEnumerator WWWDownload(string url) {
Debug.Log("インターネット接続前:" + System.DateTime.Now.ToString());
WWW www = new WWW(url);
yield return www;
Debug.Log(www.error + " " + System.DateTime.Now.ToString());
Debug.Log(www.text + " " + System.DateTime.Now.ToString());
}
まとめ
いかがでしょうか?
UnityでHTTPリクエストの処理を実装するのであれば、サーバーから永遠にレスポンスがないことを考慮してUnityWebRequestなどのタイムアウト処理を入れたほうが無難です。