简体   繁体   中英

How to get gRPC working between a Unity game client (c#/.NET) and Tonic (rust) based server

So I have a gRPC server written in Rust using the Tonic crate . I have all the proto files written and I can make requests using a Tonic based client and grpcurl so there are no issues on the server side.

I have a Unity 3D based game which I want to use as a client. Unity uses C#/.NET/Mono so in theory it should be easy to get a gRPC client working. It turns out it isn't so easy.

According to the internet (in particular https://grpc.io/blog/grpc-csharp-future/ ) we should be using the Grpc.Net.Client package. So I dropped that in to Unity using the very useful NuGetForUnity tool.

I got the following error which at least was very informative

PlatformNotSupportedException: gRPC requires extra configuration on .NET implementations that don't support gRPC over HTTP/2. An HTTP provider must be specified using GrpcChannelOptions.HttpHandler.The configured HTTP provider must either support HTTP/2 or be configured to use gRPC-Web. See https://aka.ms/aspnet/grpc/netstandard for details.

After some Googling I came across the following links which make it clear that Unity/Xamarin and others don't support Grpc.Net.Client.

https://github.com/grpc/grpc-dotnet/issues/1309#issuecomment-850303082

https://docs.microsoft.com/en-us/aspnet/core/grpc/netstandard?view=aspnetcore-6.0

In summary:

.NET implementations that don't support HTTP/2, such as UWP, Xamarin, and Unity, can use gRPC-Web as an alternative.

That sounded straight forward so I imported Grpc.Net.Client.Web and hooked it up as suggested in the article.

At least the request went through this time, but the gRPC server started causing a “Connection reset by peer” error.

Breaking out tcpdump, I realised that gRPC web makes HTTP 1.x requests which Tonic does not like.

I found the 'accept_http1' config option in Tonic which has the following description and set to to "true".

Accepting http1 requests is only useful when developing grpc-web enabled services. If this setting is set to true but services are not correctly configured to handle grpc-web requests, your server may return confusing (but correct) protocol errors.

After doing that, the server would at least accept the connection, but I started getting an error:

(StatusCode="Cancelled", Detail="No grpc-status found on response.")

I saw this issue https://github.com/grpc/grpc-dotnet/issues/1164 but it didn't help at all.

Seems like Tonic doesn't like the Grpc.Net.Client.Web implementation of gRPC-web or just doesn't support it properly.

I then spent ages trying to force gRPC-Web to use HTTP/2 by using TLS (which I'm not sure even made sense) but I couldn't get the TLS handshake to work with the Tonic server. I kept getting the vague message:

TlsException: Handshake failed - error code: UNITYTLS_INTERNAL_ERROR, verify result: (some large number)

I'm pretty sure it is because Tonic was expecting TLS 1.3 and the version of Mono that Unity uses has a maximum TLS version of 1.2 (and even that was only supported recently). I couldn't work out how to configure Tonic/Rustls to accept a lower version of TLS.

I also realised after reading the documentation more thoroughly that I would lose a lot of good gRPC features such as streaming if I used gRPC-web so I decided to avoid that method.

Does anyone know of a way to plug in a custom HTTP client into the gRPC library that does all the stuff that Unity doesn't (eg HTTP/2 and TLS 1.3)? If not does anyone know of a workaround that will let me at least get the RPC working correctly?

Thanks!

I'm not sure if this is the ideal answer, but it at least works in my situation. I ended up using Grpc.Core instead of the recommended Grpc.Net.Client to get it all working

While Grpc.Core is deprecated it still works, and the maintenance period has been extended to until May 2023.

It is feature complete, so the the main issue is not getting security updates when the maintenance period runs out, but hopefully by then Unity will have a HTTP/2 implementation!

I suspect it works because it is a wrapper over a native library that has its own HTTP implementation built into it, which means we get to bypass Unity's old implementation. This suspicion is confirmed by this comment: Why does Xamarin Android fails to send GRPC/Http2 requests?

A lot of the interfaces line up, so the only thing I had to do from a code perspective was remove Grpc.Net.Client from the project, add Grpc.Core and then replace

var channel = Grpc.Net.Client.GrpcChannel.ForAddress("http://127.0.0.1:50051");

with

 var channel = new Grpc.Core.Channel("127.0.0.1:50051", ChannelCredentials.Insecure);

However, there is a big caveat. The native libraries are provided as part of the Grpc.Core Nuget package and are not installed in the right place automatically. You can see them by downloading the nuget file manually, extracting the nuget file as a zip file and checking the runtimes folder.

Currently there is only pre-compiled binaries for the following platforms:

Grpc.Core

  • linux-arm64
  • linux-x64
  • osx-x64
  • win-x64
  • win-x86

Grpc.Core.M1

Grpc.Core.Xamarin

  • iOS
  • Android

Find the binary library for the platform(s) you want and copy it into the "Assets/Plugins" directory in your Unity project. You might need to select them in Unity and make sure all the architectures and platforms are set correctly.

You also need to ensure that the file's base name is "grpc_csharp_ext". For example, the binary in the Grpc.Core.M1 project is named "grpc_csharp_ext.arm64.dylib", and needs to be renamed to "grpc_csharp_ext.dylib" or you'll get the error:

DllNotFoundException: grpc_csharp_ext assembly: type: member:(null)

This method won't work out of the box for the other platforms. You might be able to compile your own version for other platforms if you are willing to put in the work though!

The source is at https://github.com/grpc/grpc/tree/master/src/csharp

I hope this helps someone, it took me a really long time to track down!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM