zoukankan      html  css  js  c++  java
  • GRPC代替webapi Demo。

    gRPC 是一种与语言无关的高性能远程过程调用 (RPC) 框架。

    gRPC 的主要优点是:

    • 现代高性能轻量级 RPC 框架。
    • 协定优先 API 开发,默认使用协议缓冲区,允许与语言无关的实现。
    • 可用于多种语言的工具,以生成强类型服务器和客户端。
    • 支持客户端、服务器和双向流式处理调用。
    • 使用 Protobuf 二进制序列化减少对网络的使用。

    这些优点使 gRPC 适用于:

    • 效率至关重要的轻量级微服务。
    • 需要多种语言用于开发的 Polyglot 系统。
    • 需要处理流式处理请求或响应的点对点实时服务。

    以上来自微软的文档:https://docs.microsoft.com/zh-cn/aspnet/core/grpc/index?view=aspnetcore-3.0

     个人理解:

    • gRPC采用HTTP/2协议,二进制传输,相比json,xml速度更快,更节省流量。
    • 支持流,只需要建立一次连接,适合服务间通讯。
    • 规范的接口标准。  
    • 跨语言。

    补充:

      Restful是一种架构风格,关注的是资源。

        通过每次http请求把资源拿过来,但资源怎么用是客户端的事情。

           gRpc是rpc的一个实现框架,因此关注其中的rpc远程过程调用。

        意思是在客户端调用服务器方法就像调用本地方法一样。如果这样做,那么服务器就必须要有相应的处理的方法(参数和返回值)。

        grpc在proto文件中定义了方法名和返回值,在各种语言中,我们只需要在服务器和客户端实现相应的方法即可。

    以下Demo主要体现了服务端与客户端以流式RPC的方式,并对比webapi的方式。

    *必须使用http/2,因此需要在服务器上监听端口设置。

                        //支持无tls的http/2。
                        webBuilder.ConfigureKestrel(options =>
                        {
                            options.ListenLocalhost(5000, o => o.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http2);
                        });

    *客户端需要设置

              AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

    C#自动生成代码,客户端需要从nuget安装:

      Google.Protobuf

      Grpc.Core

      Grpc.Net.ClientFactory

      Grpc.Tools

    项目文件:

      <ItemGroup>
        <Protobuf Include="ProtosDuplicate.proto" GrpcServices="Client">
        </Protobuf>
      </ItemGroup>

    服务的需要

      Grpc.Tools

      Grpc.AspNetCore.Server

      Grpc.AspNetCore

    项目文件:

      <ItemGroup>
        <Protobuf Include="Protos/Duplicate.proto" GrpcServices="Server" />
      </ItemGroup>

    该Demo模拟了一个判重的服务器和客户端。

        public interface IDuplicate
        {
            /// <summary>
            /// 将标签进入判重。
            /// </summary>
            /// <param name="tag">标签。</param>
            /// <returns>保存成功后将返回一个值。</returns>
            bool EntryDuplicate(string tag);
    
            /// <summary>
            /// 判断标签是否已经存在。
            /// </summary>
            /// <param name="tag">标签。</param>
            /// <returns>如果标签存在则返回true。</returns>
            bool DuplicateCheck(string tag);
    
            /// <summary>
            /// 删除一条标签。
            /// </summary>
            /// <param name="tag">标签。</param>
            /// <returns>返回结果。</returns>
            bool RemoveItem(string tag);
        }

    Proto配置:

    syntax = "proto3";
    
    // 命名空间。
    option csharp_namespace = "GrpcServer.Protos";
    
    package Duplicate;
    
    service Duplicater{
    
        // 进队列接口。
        rpc EntryDuplicate(stream EntryRequset) returns (stream EntryResponse);
    
        // 判重接口。
        rpc DuplicateCheck(stream DuplicateCheckRequset) returns (stream DuplicateCheckResponse);
    }
    
    // 进队列请求。
    message EntryRequset{
        // tag=1,表示在传输过程中,此数据的名字就是1。
        string tag=1;
    }
    
    // 进队后响应。
    message EntryResponse{
        bool result=1;
        string msg=2;
    }
    
    // 判重请求。
    message DuplicateCheckRequset{
        string tag=1;
    }
    
    // 判重后响应。
    message DuplicateCheckResponse{
        bool result=1;
    }

    Demo中主要实现了入判重的方法。

            /// <summary>
            /// 入判重。
            /// </summary>
            /// <param name="requestStream">请求流。</param>
            /// <param name="responseStream">响应流。</param>
            /// <param name="context">上下文。</param>
            /// <returns></returns>
            public override async Task EntryDuplicate(IAsyncStreamReader<EntryRequset> requestStream, IServerStreamWriter<EntryResponse> responseStream, ServerCallContext context)
            {
                while (await requestStream.MoveNext())
                {
                    var result = _memoryDuplicate.EntryDuplicate(requestStream.Current.Tag);
                    var msg = string.Empty;
                    if (result)
                        msg = $"{requestStream.Current.Tag} 入判重成功。";
                    else
                        msg = $"{requestStream.Current.Tag} 入判重失败,已有重复的数据";
                    _logger.LogInformation(msg);
    
                    await responseStream.WriteAsync(new EntryResponse { Result = result, Msg = msg });
                }
    
                _logger.LogInformation("本次请求已完成");
            }

    由客户端告知流传输结束,然后释放连接:

                var token = new CancellationToken();
                var response = Task.Run(async () =>
                {
                    while (await entry.ResponseStream.MoveNext(token))
                    {
                        if (entry.ResponseStream.Current.Result)
                            Console.WriteLine($"{entry.ResponseStream.Current.Msg}");
                        else
                            Console.WriteLine($"{entry.ResponseStream.Current.Msg}入判重失败。");
                    }
                });
                for (int i = 0; i < length; i++)
                {
                    SpinWait.SpinUntil(() => false, 200);
                    var msg = random.Next(0, 2000).ToString();
                    await entry.RequestStream.WriteAsync(new EntryRequset { Tag = msg });
                }
    
                Console.WriteLine("等待释放链接。");
                await entry.RequestStream.CompleteAsync();
                entry.Dispose();
                Console.WriteLine("完成");

     Grpc:

     WebApi:

     github地址:https://github.com/yeqifeng2288/GrpcDemo

  • 相关阅读:
    【BZOJ1835】[ZJOI2010]base 基站选址 线段树+DP
    【BZOJ1786】[Ahoi2008]Pair 配对 DP
    【BZOJ3956】Count 主席树+单调栈
    【BZOJ4605】崂山白花蛇草水 权值线段树+kd-tree
    【BZOJ2597】[Wc2007]剪刀石头布 最小费用流
    前端学习笔记之CSS属性设置
    前端学习笔记之HTML body内常用标签
    前端学习笔记之CSS介绍
    前端学习笔记之CSS选择器
    博客园美化技巧汇总
  • 原文地址:https://www.cnblogs.com/yeqifeng2288/p/11762579.html
Copyright © 2011-2022 走看看