GRPC is a high-performance RPC framework that is effectively used for service communication (both within and across data centers).

Open source by Google, it is currently a Cloud Native Computing Foundation (CNCF) incubator project.

Its features include:

  • Two-way flow
  • Powerful binary serialization
  • Pluggable authentication, load balancing, and health checking

In gRPC, client applications can call server B’s methods directly on server A as if it were A local object, making it easier for you to create distributed applications and microservices.

Like many RPC systems, gRPC revolves around the idea of defining services (defining the input parameters and return value types of methods that can be called remotely).

On the server side, the server implements this interface and runs the gRPC server to handle client calls.

On the client side, the client has a stub (just a client in some languages) that provides the same methods as the server.

In this article, I’ll show you how to use it. NET5 Create the gRPC service. I’ll break down some of the important underlying concepts of gRPC and give an example of communication.

1. Create a gRPC server

We will create a new dotnet project from using the gRPC service template.

If you are using Visual Studio, create a new project, then select the gRPC Service template and use GrpcAuthor as the name of the project.

1.1 The RPC Service Definition

Clients and servers communicate/communicate using Protocol Buffers: Protocol buffers are used both as the interface definition Language (IDL) for services and as the underlying message exchange format.

① Use protocol buffers to define the service interface in the. Proto file. In it, you define the input parameter and return value types of methods that can be called remotely. The server implements this interface and runs the gRPC server to handle client calls. ② After defining the service, use the Protocol Buffers compiler protoc to generate data access/transport classes from the. Proto file. This file contains the implementations of messages and methods in the service interface.

Focus on greet.proto in the VS scaffolding project Protos folder.

syntax = "proto3";

option csharp_namespace = "GrpcAuthor";

package greet;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}
Copy the code

Let’s break down the.proto file to understand the basic syntax of Protocol buffers

From the.proto file you get a rough idea of what the defined service does (to give someone a response). Here’s some syntax:

Syntax indicates the version of protocol buffers used. In this case, Proto3 is the latest version as of this writing.

②. Csharp_namespace indicates the namespace where the generated file resides. The package specifier is also used to prevent name conflicts between protocol message types.

For C#, if the csharp_namespace option is provided, the csharp_namespace value is used as the namespace;

In Java, if the option javA_Package is provided, javA_Package is used as the package name.

Service Greeter: RPC SayHello (HelloRequest) returns (HelloReply); Is a unary RPC call

④ HelloRequest and HelloReply are data structures that exchange information between the client and server. They are called messages. The number you define in a message field is non-repeatable and is used to identify the field when a message is serialized to a Protobuf because it is faster to serialize a number than the entire field name.

1.2 Implementation of service Interfaces

To generate code from.proto files, you can use the protoc compiler and C# plug-in to generate server or client code. The scaffolding project uses the Grpc.aspnetcore NuGet package: The required classes are automatically generated by the build process, you just need to add the configuration section to the project.csproj file:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
Copy the code

The generated code knows how to use Protocol Buffers to communicate with other services/clients.

The C# tool generates the GreeterBase type, which will be used as the base class to implement the gRPC service.

public class GreeterService : Greeter.GreeterBase { private readonly ILogger<GreeterService> _logger; public GreeterService(ILogger<GreeterService> logger) { _logger = logger; } public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context) { return Task.FromResult(new HelloReply { Message = "Hello " + request.Name }); }}Copy the code

MapGrpcService

();

— Start the service —

2. Create the gRPC.NET console client

Visual Studio creates a new console project called GrpcAuthorClient.

Install the following nuget Package: install-package Grpc.Net.Client install-package Google.Protobuf install-package grpc. Tools

Grpc.Net.Client contains. NET Core client;

Google.protobuf contains the Protobuf message API; Grpc.Tools Compiles Protobuf files.

① Copy the server project.. Proto file

② Change the value of csharp_namespace to GrpcAuthorClient.

③ Update the configuration section of the. Csproj file

<ItemGroup>
 <Protobuf Include="Protos\author.proto" GrpcServices="Client" />
</ItemGroup>
Copy the code

④ Main Client file:

static void Main(string[] args) { var serverAddress = "https://localhost:5001"; using var channel = GrpcChannel.ForAddress(serverAddress); var client = new Greeter.GreeterClient(channel); Var reply = client.SayHello(new HelloRequest {Name = "sz! }); Console.WriteLine(reply.Message.ToString()); Console.WriteLine("Press any key to exit..." ); Console.ReadKey(); }Copy the code

Create a GrpcChannel with the server address, then instantiate GreeterClient with the GrpcChannel object; Then use the SayHello synchronization method; When the server responds, the result is printed.

Scaffolding examples are a good place to start, but let’s talk about the other core features

3. Other core functions

3.1 Communication Mode

  • Unary RPC(Unary RPC call): the example above
  • Server Streaming RPC: A Server streaming RPC in which a client sends a request to the Server and fetches a stream to read and retrieve a series of messages. The client reads from the returned stream until there are no more messages. GRPC guarantees the order of messages in a single RPC call.
  • Client Streaming RPC in which the Client writes a series of messages and then sends them to the server again using the supplied stream. After the client finishes writing the message, it waits for the server to read the message and return a response. Similarly, gRPC guarantees the order of messages in a single RPC call
  • Bidirectional Streaming RPC: In which both parties use read/write streams to send a series of messages. The two flows run independently, so the client and server can read and write in whatever order they prefer: for example, the server can wait to receive all client messages before writing a response, or it can read one message and then write another, or some other combination of read and write. The order of messages in each flow is preserved.

3.2 the Metadata

Metadata is information (such as authentication details) about a particular RPC call in the form of a list of key-value pairs where the key is a string and the value is usually a string but can be binary data.

Metadata is opaque to the gRPC itself: it allows clients to provide invocation-related information to the server, and vice versa.

3.3 Channels

GRPC channels provide connections to gRPC servers on specified hosts and ports. It is used when creating client stubs, and you can specify channel parameters to modify the default behavior of gRPC, such as turning message compression on or off. Channels have state, both connected and idle.


4 gRPC plays table tennis

For scaffolding items, slightly modified –> table tennis

(Check gRpc bidirectional streaming communication, Timeout mechanism and exception handling):

The client sends “Gridsum” and the server sends back “musdirg”; The client sends “gridsum” again, repeating……

① Adding an Interface

rpc PingPongHello(stream HelloRequest) returns (stream HelloReply);
Copy the code

② Implement service contracts

public override async Task PingPongHello(IAsyncStreamReader<HelloRequest> requestStream,IServerStreamWriter<HelloReply> responseStream, ServerCallContext context) { try { while (! context.CancellationToken.IsCancellationRequested) { var asyncRequests = requestStream.ReadAllAsync(); Var req in asyncRequests {var send = Reverse(req.name); // Client and server "table" await foreach (var req in asyncRequests) {var send = Reverse(req.name); await responseStream.WriteAsync(new HelloReply { Message = send, Id = req.Id + 1 }); Debug.WriteLine($" {req.Id} turn, server receives {req.Name}; Start {req.Id + 1} round, server sends {send}"); } } } catch (RpcException ex) { System.Diagnostics.Debug.WriteLine($"{ex.Message}"); } catch (IOException ex) { System.Diagnostics.Debug.WriteLine($"{ex.Message}"); }}Copy the code

③ Add client code to control 5s final disconnection

using (var cancellationTokenSource = new CancellationTokenSource( 5* 1000)) { try { var duplexMessage = client.PingPongHello(null, null, cancellationTokenSource.Token); await duplexMessage.RequestStream.WriteAsync(new HelloRequest { Id = 1, Name = "gridsum" }) ; var asyncResp = duplexMessage.ResponseStream.ReadAllAsync(); await foreach (var resp in asyncResp) { var send = Reverse(resp.Message); await duplexMessage.RequestStream.WriteAsync(new HelloRequest {Id= resp.Id, Name = send }); Console.WriteLine($" {resp.Id} turn, client receives {resp.Message}, client sends {send}"); }} Catch (RpcException ex) {Console.WriteLine(" It is time to play table tennis (client breaks gRpc connection after 5s) "); }}Copy the code

Github.com/zaozaoniao/…

conclusion

GRPC is a high-performance RPC framework with pluggable authentication and load balancing capabilities. Define structured data using Protocol buffers; Structured data is written and read in various data streams using source code generated automatically in different languages.

In this article, you learned how to define service interfaces using protocol buffers (version 3) and how to implement services using C#. Finally, you created the “Playing ping-pong “Demo using gRPC bidirectional streaming communication.

Additional Resources

  • Developers.google.com/protocol-bu…
  • www.grpc.io/docs/what-i…
  • Docs.microsoft.com/en-us/dotne…