zoukankan      html  css  js  c++  java
  • .net core 用grpc实现微服务

    GRPC 是Google发布的一个开源、高性能、通用RPC(Remote Procedure Call)框架。提供跨语言、跨平台支持。以下以.NET Core 使用控制台、docker中演示如何使用GRPC框架。

       

    软件版本

    .net core :1.0.1

    GRPC:1.0.1-pre1

       

       

    1.定义服务

    使用proto3语法定义一个服务,主要测试package、import、常用类型的测试,

    proto3语法: https://developers.google.com/protocol-buffers/docs/proto3

       

    定义一个result.proto

       

    syntax = "proto3";

    package App.RPC.Model;

    message Response{

    bool sucess=1;

    string message=2;

    }

       

    定义RPCDemoService.proto文件如下:

    syntax = "proto3";

    package App.RPC.Service;

    import "result.proto";

       

    service RPCDemoService{

    rpc Add(DemoRequest) returns (App.RPC.Model.Response){}

    rpc GetById(DemoId) returns (DemoRequest){}

    rpc Get(Search) returns (DemoList){}

    }

    message DemoId{

    int32 Id=1;

    }

       

    message Search{

    int32 page=1;

    int32 size=2;

    string query=3;

    }

       

    message DemoRequest{

    string Id=1;

    int32 CommentId=2;

    bool IsDeleted=3;

    }

       

    message DemoList{

    repeated DemoRequest details = 1;

    }

       

    2.将服务生成类文件:

    项目引用nuget包Grpc.Tools 1.0.0 或通过命令安装这个程序包,然后找到文件路径

    先配置packagesGrpc.Tools1.0.0 oolswindows_x64protoc.exe环境变量

    protoc.exe --csharp_out=d:grpcdemocode --grpc_out=d:grpcdemocode --plugin=protoc-gen-grpc=yourpath.nugetpackagesGrpc.Tools1.0.0 oolswindows_x64grpc_csharp_plugin.exe result.proto

    protoc.exe --csharp_out=d:grpcdemocode --grpc_out=d:grpcdemocode --plugin=protoc-gen-grpc=yourpath.nugetpackagesGrpc.Tools1.0.0 oolswindows_x64grpc_csharp_plugin.exe RPCDemoService.proto

       

    3.创建.net core 类型项目App.RPCDemo

    Project.json文件内容如下:

    {

    "version": "1.0.0-*",

    "dependencies": {

    "Grpc.Tools": "1.0.0"

    },

    "frameworks": {

    "netstandard1.6": {

    "imports": "dnxcore50",

    "dependencies": {

    "NETStandard.Library": "1.6.0",

    "Grpc": "1.0.1-pre1",

    "Grpc.Core": "1.0.1-pre1",

    "Google.Protobuf": "3.1.0",

    "System.Interactive.Async": "3.0.0"

    }

    }

    }

    }

       

    4.创建服务端App.RPCDemoServer

    因为要在docker 中进行测试,官方网站并没有docker 下的例子,也没有说这个rpc在生产环境中如何hosting; 通过查看.net core的host源码在Microsoft.AspNetCore.Hosting.Internal.ApplicationLifetime这个类文件有实现,把这个文件的内容直接copy过来

    类的部分内容如下:

    private readonly CancellationTokenSource _startedSource = new CancellationTokenSource();

    private readonly CancellationTokenSource _stoppingSource = new CancellationTokenSource();

    private readonly CancellationTokenSource _stoppedSource = new CancellationTokenSource();

       

    /// <summary>

    /// Triggered when the application host has fully started and is about to wait

    /// for a graceful shutdown.

    /// </summary>

    public CancellationToken ApplicationStarted => _startedSource.Token;

       

    /// <summary>

    /// Triggered when the application host is performing a graceful shutdown.

    /// Request may still be in flight. Shutdown will block until this event completes.

    /// </summary>

    public CancellationToken ApplicationStopping => _stoppingSource.Token;

       

    /// <summary>

    /// Triggered when the application host is performing a graceful shutdown.

    /// All requests should be complete at this point. Shutdown will block

    /// until this event completes.

    /// </summary>

    public CancellationToken ApplicationStopped => _stoppedSource.Token;

       

    google Grpc中的server类型没有接口,定义一个接口Iserver

    namespace App.RPC.Core

    {

    public interface IServer

    {

    void Start();

       

    void Stop();

       

    Status State { get; set; }

    }

       

    public enum Status

    {

    None,

    Stop,

    Running

       

    }

    }

       

    在创建一个hosting 文件内容如下:

       

    public static class RpcHostExtensions

    {

    public static void Run(this IServer server)

    {

    var done = new ManualResetEventSlim(false);

    using (var cts = new CancellationTokenSource())

    {

    Action shutdown = () =>

    {

    if (!cts.IsCancellationRequested)

    {

    server.Stop();

    Console.WriteLine("Rpc Service is shutting down...");

    cts.Cancel();

    }

    done.Wait();

    };

       

    #if NETSTANDARD1_5

    var assemblyLoadContext = AssemblyLoadContext.GetLoadContext(typeof(WebHostExtensions).GetTypeInfo().Assembly);

    assemblyLoadContext.Unloading += context => shutdown();

    #endif

    Console.CancelKeyPress += (sender, eventArgs) =>

    {

    shutdown();

    // Don't terminate the process immediately, wait for the Main thread to exit gracefully.

    eventArgs.Cancel = true;

    };

       

    server.Run(cts.Token, "Rpc Service started. Press Ctrl+C to shut down.");

    done.Set();

    }

    }

       

    /// <summary>

    /// Runs a web application and block the calling thread until token is triggered or shutdown is triggered.

    /// </summary>

    /// <param name="host">The <see cref="IWebHost"/> to run.</param>

    /// <param name="token">The token to trigger shutdown.</param>

    public static void Run(this IServer server, CancellationToken token)

    {

    server.Run(token, shutdownMessage: null);

    }

       

    private static void Run(this IServer server, CancellationToken token, string shutdownMessage)

    {

    if (server.State != Status.Running)

    {

    server.Start();

    }

       

    var applicationLifetime = new ApplicationLifetime();

    if (!string.IsNullOrEmpty(shutdownMessage))

    {

    Console.WriteLine(shutdownMessage);

    }

       

    token.Register(state =>

    {

    ((ApplicationLifetime)state).StopApplication();

    },

    applicationLifetime);

       

    applicationLifetime.ApplicationStopping.WaitHandle.WaitOne();

       

    }

    }

       

    实现服务RPCDemoImpl

    public class RPCDemoImpl : RPCDemoService.RPCDemoServiceBase

    {

    public override Task<Response> Add(DemoRequest request, ServerCallContext context)

    {

     

    return Task.FromResult(new Response { Message = "成功" + context.Host + DateTime.Now.Ticks.ToString(), Sucess = true });

    }

       

    public override Task<DemoList> Get(Search request, ServerCallContext context)

    {

    var result = new DemoList();

    result.Details.Add(new DemoRequest()

    {

    CommentId = 1,

    Id = DateTime.Now.Ticks.ToString(),

    IsDeleted = false

    });

    return Task.FromResult(result);

       

    }

       

    public override Task<DemoRequest> GetById(DemoId request, ServerCallContext context)

    {

    return Task.FromResult(new DemoRequest()

    {

    CommentId = request.Id,

    Id = DateTime.Now.Ticks.ToString(),

    IsDeleted = false

    });

    }

    }

       

    program文件如下:

    public class Program

    {

    public static void Main(string[] args)

    {

    string host = "0.0.0.0";

    int port = 9007;

    var dic = Common.GetArgs(args);

    if (dic != null && dic.Count > 0)

    {

    string tempHost;

    string tempPort;

    if (dic.TryGetValue("host", out tempHost))

    {

    host = tempHost;

    }

    if (dic.TryGetValue("port", out tempPort))

    {

    port = Convert.ToInt32(tempPort);

    }

    }

       

    GrpcServer server = new GrpcServer

    {

    Services = { RPCDemoService.BindService(new RPCDemoImpl()) },

    Ports = { new ServerPort(host, port, ServerCredentials.Insecure) }

    };

    Console.WriteLine("Google Grpc Starting");

    foreach (var item in server.Ports)

    {

    Console.WriteLine(string.Format("RPC server {0} listening on port {1}", item.Host, item.Port));

    }

    server.Run();

       

    }

    }

       

    编译发布后运行如下:

       

    客户端程序

    public static void Main(string[] args)

    {

    string host = "127.0.0.1";

    string port = "9007";

    long length = 10;

    var dic = Common.GetArgs(args);

    if (dic != null && dic.Count > 0)

    {

    string tempHost;

    string tempPort, tempLength;

       

    if (dic.TryGetValue("host", out tempHost))

    {

    host = tempHost;

    }

    if (dic.TryGetValue("port", out tempPort))

    {

    port = tempPort;

    }

       

    if (dic.TryGetValue("repeat", out tempLength))

    {

    length = Convert.ToInt64(tempLength);

    }

    }

       

    Channel channel = new Channel(string.Format("{0}:{1}", host, port), ChannelCredentials.Insecure);

    var client = new RPCDemoService.RPCDemoServiceClient(channel);

       

    var stopwatch = Stopwatch.StartNew();

    for (var i = 0; i < length; i++)

    {

       

    var reply = client.GetById(new DemoId() { Id = i });

    Console.WriteLine("receive" + JsonConvert.SerializeObject(reply));

    }

    stopwatch.Stop();

       

    Console.WriteLine(string.Format("repeat={0}, time={1} Milliseconds, time/repeat={2}", length, stopwatch.ElapsedMilliseconds, stopwatch.ElapsedMilliseconds / (float)length));

    Console.ReadKey();

       

    channel.ShutdownAsync().Wait();

       

    }

       

    编译发布运行如下:

       

       

       

    Centos 7测试如下:

    服务端

    [demo@node139 App.RPCDemoServer]$ docker run --name rcpdemo -d -p 9007:9007 grpcemoserver

    966b44acb2e0757c45b7dcf2d865e424dc764e50844e312ef2ea374999992a55

    客户端

    [demo@node139 App.RPCDemoClient]$ dotnet App.RPCDemoClient.dll host=192.168.190.139 port=9007 repeat=1

    receive{"Id":"636138810040717530","CommentId":0,"IsDeleted":false}

       

    docker中演示和源码地址:https://github.com/yjpgfwxf/App.GRPCDemo.NetCore

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

  • 相关阅读:
    python之进程和线程2
    Python学习笔记7:yield生成迭代器
    Python学习笔记6:装饰器
    Python学习你急5:文件打开与处理
    Python学习笔记4:集合方法
    Python学习笔记3:字典方法
    Python学习笔记2:列表操作方法详解
    Python学习笔记1:字符串方法
    番外篇:Vim使用方法
    Day12: 正则表达式
  • 原文地址:https://www.cnblogs.com/liuyuhua/p/6031210.html
Copyright © 2011-2022 走看看