UnityでHTTPリクエストの処理を実装することがあります。
HTTPリクエストする際、忘れては行けないのが、タイムアウト処理です。
タイムアウト処理がないと、永遠にサーバーからのレスポンスを待ち続けることになり、ゲームが全く進行しないという致命的な不具合を引き起こします。
UnityWebRequestによるタイムアウトの実装について
タイムアウトは、Unity5.4からUnityWebRequestが使えるようになり、標準でタイムアウト処理を実装できるようになりました。
対処方法は、
UnityWebRequest.timeoutに1以上の数字をセットするだけです。
詳しくは、「地味に必要!UnityにてHTTPリクエストにタイムアウト処理を実装する」を参考にしてください。
しかし、IOSではタイムアウトが効かないケースが有る
本来であれば、UnityWebRequest.timeoutに値をセットすることでタイムアウトを実装できますが、IOS端末で動作テストしたらUnityWebRequest.timeoutが反映されず、サーバーから全くレスポンスがない状態になる問題が発生しました。
UnityWebRequest.timeout = 5とした場合、本来であれば5秒でタイムアウトが発生しますが、なぜか5分経ってもレスポンスが返ってこないケースがあります。
この問題は、20回リクエストしたら1回の割合で発生するため、厄介な問題と言えます。
問題が発生すると、レスポンスをずっと待ち続けるためゲームが進行しなくなってしまいます。
このような問題が発生したら、リクエスト送信後、一定時間が経ったら強制的に通信を切断するなどしてタイムアウトさせます。次の項目で具体的な実装方法を掲載します。
タイムアウトを独自に実装する
タイムアウト処理を独自に実装する例を記載します。
やっていることは、「AsyncOperation op = www.Send()」を呼び出しリクエストを送信したら、タイムアウト時間(サンプルソースコードでは3秒)を決め、その時間になったら通信を強制的に終了させています。
//UnityWebRequestでhttpリクエストを実装する
IEnumerator UnityWebRequestDownload(string url) {
float addTime = 0f;//タイムアウト監視
UnityWebRequest www = UnityWebRequest.Get(url);
//タイムアウトを3秒に設定する(IOSではなぜかwww.timeout >0の値をセットしてもレスポンスが来ないことがあるのでコメント化)
// www.timeout = 3;
Debug.Log("インターネット接続前:" + System.DateTime.Now.ToString());
//リクエスト送信(データのダウンロードを監視するため以下のように実装する)
AsyncOperation op = www.Send();
while (true)
{
if (op.isDone == false) {
//通信中
yield return null;
addTime += Time.deltaTime;
if ((int)addTime >= 3) {
//3秒経過したらループを抜ける
//通信を切断する
www.Abort ();
break;
}
} else {
//通信完了でループを抜ける
break;
}
}
Debug.Log(www.error + " " + System.DateTime.Now.ToString());
Debug.Log(www.downloadHandler.text + " " + System.DateTime.Now.ToString());
}
Android端末では、UnityWebRequest.timeoutに値を設定すればタイムアウトが動作するようです。
もし、UnityWebRequest.timeoutに値をセットしてもタイムアウトが発生しないのであれば、一定時間で強制的に通信を切断し、再接続させるような実装をしてみてはいかがでしょうか?
私が携わっているゲームでは、この記事で紹介した方法で解決しています。