RPC Framework Based on DotNet Core (I) Quick Start of DotBPE.RPC

Keywords: Google github git encoding

0x00 introduction

DotBPE. RPC is an RPC framework based on dotnet core. Its father, DotBPE, aims to achieve an out-of-the-box micro-service framework, but it is almost meaningful, only in the stage of conception and attempt. But anyway, RPC is the foundation of micro-service, let's talk about the implementation of RPC first. The default implementation of DotBPE.RPC underlying communication is based on DotNetty This is a Netty implementation of C# developed by Microsoft Azure team. It's very cool. Of course, you can also replace it with other Socket communication components. DotBPE.RPC uses the default protocol name Amp, and Google's Proteobuf3 for encoding and decoding, but these default implementations are replaceable.

Source address: https://github.com/xuanye/dotbpe.git

<!--more-->

0x01 About Amp Protocol and Google Protobuf

Amp(A Message Protocol)

Amp(A Message Protocol), which is called a message protocol in Chinese, is a message protocol implemented by DotBPE.RPC by default. In practice, it is not necessary to know how messages are coded, decoded and transmitted, but it is helpful to understand the framework. The basic structure of the protocol is shown in the following figure:

      0        1 2 3 4   5 6 7 8     9     10 11     12 13   <length>-14
+------------+----------+---------+------+-------+---------+------------+
| <ver/argc> | <length> |  <seq>  |<type>|<serId>| <msgid> |   <data>   |
+------------+----------+---------+------+-------+---------+------------+

The default header length of Amp protocol is 14 bytes and does not contain extended header.
Number 0: ver/argc// is the version number, temporarily, the default is 0
Bit 1-4: length // is the total length of the package (including the length of the head)
Bit 5-8: sequence // is the message sequence number, which corresponds to the request < - > response Number 9: type // Message type, with five present values, as follows: > Request = 1, Response = 2, Notify = 3,NotFound = 4, ERROR = 5
Bits 10-11: serviceId//message ID ushort type
Bits 12-13: msgId//message ID ushort type
In Amp protocol, serviceId identifies a class of requests, similar to modules in applications, while msgId identifies specific methods in modules.

Then follow the actual data.

Google Protobuf

Google Protocol Buffer (hereinafter referred to as Protobuf) is a mixed language data standard within Google. At present, more than 48,162 message format definitions and more than 12,183. proto files are being used. They are used in RPC systems and persistent data storage systems.

Protocol Buffers is a portable and efficient structured data storage format, which can be used for structured data serialization, or serialization. It is very suitable for data storage or RPC data exchange format. It can be used for language-independent, platform-independent and extensible serialized structured data formats in communication protocols, data storage and other fields. API s in many languages are currently available, including C++, C#, GO, JAVA, PYTHON

My previous blog Using CSharp to write Google Protobuf plug-ins It has been introduced that if we write plug-ins, we can define proto files and generate the code we need.

In DotBPE.RPC, I use protobuf as the description file of the service, and generate the proxy classes of the server and client through a custom plug-in.

0x02 Quick Start

0. premise

Because DotBPE is based on dotnet core, you must have a dotnet core development environment locally.
Use github managed code, so you must have installed the git client
You need to generate template code through protoc, so you must have installed the google protobuf command line tool

1. Download the sample program

In order to explain our quick start program, you need a sample code that can run locally. Downloading the sample code I've written from github allows you to quickly build programs without some tedious but necessary steps.

>$ # Clone the repository to get the example code:    
>$ git clone https://github.com/xuanye/dotbpe-sample.git  
>$ cd dotbpe-sample  

Use VS2017 or VSCode to open the downloaded code. The directory structure is as follows:

If you use VS2017, you can automatically help you back to the original. If you use VSCode, you need to run dotnet restore download dependency. After success, you can use dotnet build to compile and see the result: It looks perfect.

2. Running program

Run Server

>$ cd HelloDotBPE.Server   
>$ dotnet run

Run Client

>$ cd HelloDotBPE.Client   
>$ dotnet run

Congratulations! A Server/Client application has been run using DotBPE.RPC.

3. Let's take a look at the code.

3.1 Service Description File proto

First of all, the proto extension file in the DotBPE.RPC framework. All projects need this file. My article is about how to extend the proto. Blog With more detailed introduction, I won't repeat it here.

//dotbpe_option.proto file

syntax = "proto3";
package dotbpe;

option csharp_namespace = "DotBPE.ProtoBuf";

import "google/protobuf/descriptor.proto";

//Extended services
extend google.protobuf.ServiceOptions {
  int32 service_id = 51001;
  bool disable_generic_service_client = 51003; //Prohibit client code generation
  bool disable_generic_service_server = 51004; //Prohibit the generation of server-side code
}
extend google.protobuf.MethodOptions {
  int32 message_id = 51002;
}

extend google.protobuf.FileOptions {
  bool disable_generic_services_client = 51003; //Prohibit client code generation
  bool disable_generic_services_server = 51004; //Prohibit the generation of server-side code
  bool generic_markdown_doc = 51005; //Document generation is not useful in this example
  bool generic_objectfactory = 51006; //Whether or not to generate object factories is not useful in this example
}

The following service description file, greeter.proto, is the real example service description file: Simpler, define a Greeter Rpc service, and define a Hello method

//greeter.proto
syntax = "proto3";
package dotbpe;

option csharp_namespace = "HelloDotBPE.Common";

// Introducing extensions
import public "dotbpe_option.proto";

// Define a service
service Greeter {
  option (service_id)= 100 ;//Message ID, global must be unique
  // Sends a greeting
  rpc Hello (HelloRequest) returns (HelloResponse) {
    option (message_id)= 1 ;//Set the message ID, unique within the same service
  }

}

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

The template code is generated by protoc tool, and the code in the example is generated in HelloDotBPE. Common_g directory. Students who can run shell commands locally can go directly to the HelloDotBPE.Common_g directory. The dotbpe-samplescriptgenerate directory runs sh generate_hello.sh (cgywin is usually installed under windows). Students who cannot run can also run the command line directly under Hello DotBPE directory.

protoc -I=../protos --csharp_out=./HelloDotBPE.Common/_g/ --dotbpe_out=./HelloDotBPE.Common/_g/   ../protos/dotbpe_option.proto ../protos/greeter.proto  --plugin=protoc-gen-dotbpe=../../tool/protoc_plugin/Protobuf.Gen.exe

Of course, I recommend that you install the following cgywin runtime environment to run some common commands on unix. At the same time, some scripts of the development environment can be shared when deployed to the formal environment.

3.2 Server Code

Service implementation:

// Service implementation code
public class GreeterImpl : GreeterBase 
{ 
   public override Task<HelloResponse> HelloAsync(HelloRequest request)
   {
        // Return directly to Hello Name
       return Task.FromResult(new HelloResponse() { Message = "Hello " + request.Name });
   }
}

Server Startup Class

 public class Startup : IStartup
    {

        public void Configure(IAppBuilder app, IHostingEnvironment env)
        {

        }

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddDotBPE(); // Adding DotBPE.RPC Core Dependencies
            services.AddServiceActors<AmpMessage>(actors => {
                actors.Add<GreeterImpl>(); // Registration Service Implementation
            });

            return services.BuildServiceProvider();
        }
    }

Start the server

   class Program
    {
        static void Main(string[] args)
        {
            Console.OutputEncoding = System.Text.Encoding.UTF8;

            //Output debug log in console
            DotBPE.Rpc.Environment.SetLogger(new DotBPE.Rpc.Logging.ConsoleLogger());

            var host = new RpcHostBuilder()
                .UseServer("0.0.0.0:6201") //Binding Local Port 6201
                .UseStartup<Startup>()
                .Build();

            host.StartAsync().Wait();

            Console.WriteLine("Press any key to quit!");
            Console.ReadKey();

            host.ShutdownAsync().Wait();

        }
    }

3.3 Client Code

 class Program
    {
        static void Main(string[] args)
        {
            Console.OutputEncoding = Encoding.UTF8;

            var client = AmpClient.Create("127.0.0.1:6201"); //Establishing Link Channels
            var greeter = new GreeterClient(client); //Client proxy class

            while (true)
            {
                Console.WriteLine("input your name and press enter:");
                string name = Console.ReadLine();
                if ("bye".Equals(name))
                {
                    break;
                }
                try
                {
                    var request = new HelloRequest() { Name = name };
                    var result = greeter.HelloAsync(request).Result;                  
                    Console.WriteLine($"---------------receive form server:{result.Message}-----------");

                }
                catch (Exception ex)
                {
                    Console.WriteLine("Errors occurred:" + ex.Message);
                }
            }
            Console.WriteLine($"---------------close connection-----------");
            client.CloseAsync();
        }
    }

0x03 Next Step

In the next article, I will describe in detail the main classes and invocation relationships in DotBPE.RPC, and how to use DotNetty to achieve RPC communication. In fact, I'm writing a more complex example. https://github.com/xuanye/PiggyMetrics.git, This was originally a sample program of spring cloud. I used DotBPE to transform and describe the application of DotBPE in real scenes with examples. Including service registration and discovery, inter-service invocation, disclosure of HttpApi, monitoring and inspection functions, and through practice to further improve the DotBPE. Preliminary functions have been implemented, but there is no time to write documentation. The implementation of this system will be described in detail later in this series.

Posted by gofeddy on Fri, 11 Jan 2019 13:15:11 -0800