こんにちは!
システム開発部のK.Mです。
今回の記事の経緯
UnityではUnityWebRequest()という通信するためのAPIが標準で用意されていますが、
HTTP/1.1だったりスレッド周りで画像などのリソースを大量にDLする時に使い勝手が悪かったりで、何とか簡単に通信出来ないのか?というお話です。
確認環境
OS:Mac
Unity:2021.3.12f1
単純にAPIと通信するなら
UnityWebRequest()で十分だと考えています。
しかし、画像などのアセットデータの小サイズ・多数を同タイミングでDLしたいとかだったり、非同期で通信したいとかのケースで困りがちです。
また、Unityのバージョンによっては不具合があったりで、正常に動かないこともあったりもするので要注意となります。参考1 参考2
諸々考えるとアセットの多重DLなどの処理には、HTTP/2で通信したいところです。
手っ取り早くHTTP/2で接続したい
BestHTTP/2などの外部アセットを使うのが手っ取り早いです。
ただ、ブラックボックスな外部アセットを使用したくない・使用できない場合はどうしたら良いのでしょうか?
Unity標準でHTTP/2対応してないの?
Unity2021.3のバージョンの場合、.NET Standard2.1(.NET4.x)に対応しているようなのでHttpClient
を使ってHTTP/2が使えないのかと考えつきました?
2018.3以前だと.NET3.5なので、HTTP/2はそもそもサポートされていないので論外。
その1:.NETで使えるHttpClient
バージョン指定のためのプロパティが増えているので、それを使えばHTTP/2が使えそうなので試してみました。
上記のようにUnityではエラーが出てしまっており、.NET Standard2.1のHttpClientにはバージョン指定のプロパティが存在しませんでした。 そのため、現時点でのUnity標準のHttpClientではHTTP/2は使えないようです。
.NET5以上であれば、DefaultRequestVersion
というプロパティが存在しているので、
static readonly HttpClient httpClient = new HttpClient(); { DefaultRequestVersion = new Version(2, 0) };
という形でHTTP/2の指定が可能となっている。
または、HttpRequestMessage
にもVersionが存在するので定義時に指定も可能になっています。
var request = new HttpRequestMessage(HttpMethod.Get, requestEndPoint) { Version = new Version(2,0) };
か
var request = new HttpRequestMessage(HttpMethod.Get, requestEndPoint); request.Version = new Version(2,0);
という形で指定が可能となっています。
一先ず、UnityではHttpClient
のDefaultRequestVersion
は使えないが、HttpRequestMessage
でバージョンを指定する形は可能そうなのでやってみました。
実装一部抜粋
// HttpClient定義 static readonly HttpClient httpClient = new HttpClient(); --- // HttpRequestMessage宣言時にバージョン指定してログでバージョン確認 HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestEndPoint) { Version = new Version(2,0) }; UnityEngine.Debug.Log("Request HTTP/" + request.Version);
HTTP/1.1かHTTP/2のどちらかになったかは、レスポンスとして受け取るHttpResponseMessage
のResult内のVersionに情報が入っていますので
// レスポンス内容からバージョン出力 response = httpClient.SendAsync(request); UnityEngine.Debug.Log("Response HTTP/" + response.Result.Version);
のようにログ出力して動作させてみます。
結果、リクエスト時にはHTTP/2で指定しているにも関わらずレスポンスにてHTTP/1.1になってしまっておりました。
比較確認のために、.NET7のc#(コンソールアプリ)で同じような形で実装して確認すると下記にように、HTTP/2で動いていましたので、Unityの.NETだとやはりダメなようです。
その2:gRPC
少し途方に暮れていましたが、Unityが対応しているgRPCでHTTP/2が使えるじゃないか!ということで試してみようと調査してみましたが、
Grpc.Net.Clientでは、HttpClientが内部で動いている
という情報があり、Unity標準で使えるgRPCが結局HTTP/1.1までしか出来なさそうなので断念しました。
念のため、事の真相を確かめるべくGrpc.Net.Clientの軽くソースコードを覗いてみました。Grpc周りのソースコード
src/dotnet-grpc/Commands/CommandBase.csにて
HttpClient
が定義されているので、恐らくHttpClient
が動いているものと考えられそうです。
更にsrc/Grpc.Net.Client.Web/README.mdのReadMeに
HttpRequestMessage.Version
の記載があったので、System.Net.Http
が使われていそうです。
HttpVersion: HTTP protocol Version used to set HttpRequestMessage.Version on the underlying gRPC HTTP request. gRPC-Web doesn't require a specific version and doesn't override the default unless specified.
最終奥義:自前でHTTP/2が使えるように実装する
現時点でのUnityだとアセットストアから外部アセットを導入する以外には簡単にHTTP/2は使えなさそうなので、
- libcurlなどをラッパーにして独自で実装する
- nugetで色々パッケージを入れて整合性を取っていく
という方法もありそうですが、OS毎の考慮が必要だったりと中々に茨の道になりそうかと考えており、今回の記事上ではここまでとしたいです。
結論
早く、Unityで.NET CoreCLRを使えるように頑張っていただきたいものです。
リベル・エンタテインメントでは、このような最新技術などの取り組みに興味のある方を募集しています。もしご興味を持たれましたら下記サイトにアクセスしてみてください。
https://liberent.co.jp/recruit/