LoginSignup
9
5

More than 5 years have passed since last update.

UnityでgRPCを動かす

Last updated at Posted at 2018-04-14

準備

前提

Unity + gRPCでは、MagicOnionというライブラリが有名ですが、ここではそれを使いません。
ただし、MagicOnionの修正内容は参考にしました...

以下をUnityプロジェクトに入れる

  • gRPCのC#のソースコード
    grpc/src/csharp/Grpc.Core
  • protobufのC#のソースコード
    protobuf/csharp/src/Google.Protobuf

エラーを粛々と取り除く

IAsyncEnumeratorが無いと怒られる

Assets/Grpc.Core/IAsyncStreamReader.cs(53,46): error CS0246: The type or namespace name `IAsyncEnumerator' could not be found. Are you missing an assembly reference?

IAsyncEnumeratorというインターフェースが無く、コンパイルエラーが出ますので、以下のような定義を追加します。

public interface IAsyncEnumerator<T> : IDisposable
{
    T Current { get; }
    Task<bool> MoveNext(CancellationToken token);
}

MoveNextの引数がないと言われる

Assets/Grpc.Core/Internal/ServerCallHandler.cs(69,69): error CS1501: No overload for method `MoveNext' takes `0' arguments

これは、Grpc.CoreがRx.NETに依存しているためこのようなエラーが表示されます。
なので、さらに以下のコードを追加します(namespaceやファイルの配置場所はそれぞれの事情に合わせてやってね)

    public static class AsyncEnumerator
    {
        public static Task<bool> MoveNext<T>(this IAsyncEnumerator<T> enumerator)
        {
            if (enumerator == null)
                throw new ArgumentNullException(nameof(enumerator));

            return enumerator.MoveNext(CancellationToken.None);
        }
    }

これは、Rx.NETのコードの中身そのままです。
Rx.NETまでUnityに入れようか悩みましたが、UniRxの競合とかとも考えられるためこの程度にしています。

この時点でコンパイルが通る

エラーが出なくなりました。では、次に実行してみましょう。

デバッグ実行用のSSLの証明書がないと言われる

実行するとこのエラーが出ました

IOException: Error loading the embedded resource "Grpc.Core.roots.pem"

SSLの証明書がない場合のエラーと考察し、どうしようかと考えていましたがここで、MagicOnion の修正方法を参考にさせていただきました。DefaultSslRootsOverride.cs を以下のように書き換えます。まあ、中身はまるっとその処理を無視するような内容です。


using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;

namespace Grpc.Core.Internal
{
    /// <summary>
    /// Overrides the content of default SSL roots.
    /// </summary>
    internal static class DefaultSslRootsOverride
    {
        //const string RootsPemResourceName = "Grpc.Core.roots.pem";
        static object staticLock = new object();

        /// <summary>
        /// Overrides C core's default roots with roots.pem loaded as embedded resource.
        /// </summary>
        public static void Override(NativeMethods native)
        {
            lock (staticLock)
            {
                //var stream = typeof(DefaultSslRootsOverride).GetTypeInfo().Assembly.GetManifestResourceStream(RootsPemResourceName);
                //if (stream == null)
                //{
                //    throw new IOException(string.Format("Error loading the embedded resource \"{0}\"", RootsPemResourceName));
                //}
                //using (var streamReader = new StreamReader(stream))
                //{
                //    var pemRootCerts = streamReader.ReadToEnd();
                //    native.grpcsharp_override_default_ssl_roots(pemRootCerts);
                //}
            }
        }
    }
}

これはMagicOnionのソースコードそのままです。
これで、この実行時のエラーは出なくなります。

DllNotFoundException: grpc_csharp_ext

grpc_charp_exが無いとエラーが表示されます。

DllNotFoundException: grpc_csharp_ext
Grpc.Core.Internal.NativeLogRedirector.Redirect (Grpc.Core.Internal.NativeMethods native) (at Assets/Grpc.Core/Internal/NativeLogRedirector.cs:49)

なので、それを入手してDLLをAssets配下に置く必要があるのですが、ここで自分は手間取りました。
Ubuntsu on Windowsを使っていたせいなのかはわからないですが、grpc本家のREADMEを読みつつビルドを試しましたが、うまくいかず、結局サンプルコードをVisual Studioでビルドし、NuGetパッケージの中かからdllを抜き出すということをしました

参考

なんだかんだあって、grpc_csharp_ext.dllをUnityプロジェクトに入れる

ここで、grpcのレポジトリ内にあるサンプルプロジェクトをビルドし、サーバーを立ち上げます。
https://github.com/grpc/grpc/tree/master/examples/csharp/helloworld

この中身をVisual Studioでビルドするだけでサーバー側のプログラムまでビルドされるので、ビルドしたサーバー側のexeファイルを立ち上げます。Windows以外の環境であれば、READMEの手順の通りに .NET Core インストールしつつビルドすることで実行できるかと思います。

クライアント側のサンプルコードを参考にしつつUnity側のプログラムを書く

まず、gRPC自体のサンプルプロジェクトには .proto と言われるサーバー側との通信規約をもとにしたコードもあるので、それをUnityプロジェクトに入れます。
3bdce428a37fe5aba1e59e6acdbf54b8.png

ここにある HelloWorld.cs/HelloWorldGRPC.cs がそれです。
これは、gRPCのコード生成プログラムによって吐かれるコードですがサンプルプロジェクトには含まれています。

UnityからCallする処理を入れる

以下のようなコードを書きます


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Grpc.Core;
using Helloworld;


public class TestGrpc : MonoBehaviour 
{
    void Start () 
    {
        Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);

        var client = new Greeter.GreeterClient(channel);
        String user = "Test UserName";

        var reply = client.SayHello(new HelloRequest { Name = user });
        Debug.Log("Greeting: " + reply.Message);
    }
}

これは、gRPCのC#サンプルプロジェクトの中身をそのままUnityのStartに入れ込んだだけです。
適当なGameObjectにこれをアタッチして実行します。
サーバー側のプログラムを立ち上げた上で実行すると、以下のようにちゃんとレスポンスを受け取れました!

d77a882b1dc6e1bce7cc29c7ad487ddf.png

その他

Android/iOSで動かすには、grpc_csharp_ext.dll をそれぞれのプラットフォームごとコンパイルするという苦行が待ってます。
https://github.com/grpc/grpc/blob/master/src/csharp/experimental/README.md
こちらにそのやり方は書かれてますが、まだiOSはTBD扱いです。。。
UniRxの作者の方が、いろいろやり取りされているので、できるんだと思います。
(grpc_csharp_extの中身はCのコードなのでXCodeでゴニョゴニョするとできるはず)

次は各プラットフォームの対応 + リアルタイムチャットなどをgRPCで出来たらなと思います。

9
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5