GRPC代替webapi Demo。

gRPC 是一種與語言無關的高性能遠程過程調用 (RPC) 框架。git

gRPC 的主要優勢是:github

  • 現代高性能輕量級 RPC 框架。
  • 協定優先 API 開發,默認使用協議緩衝區,容許與語言無關的實現。
  • 可用於多種語言的工具,以生成強類型服務器和客戶端。
  • 支持客戶端、服務器和雙向流式處理調用。
  • 使用 Protobuf 二進制序列化減小對網絡的使用。

這些優勢使 gRPC 適用於:web

  • 效率相當重要的輕量級微服務。
  • 須要多種語言用於開發的 Polyglot 系統。
  • 須要處理流式處理請求或響應的點對點實時服務。

以上來自微軟的文檔:https://docs.microsoft.com/zh-cn/aspnet/core/grpc/index?view=aspnetcore-3.0json

 我的理解:api

  • gRPC採用HTTP/2協議,二進制傳輸,相比json,xml速度更快,更節省流量。
  • 支持流,只須要創建一次鏈接,適合服務間通信。
  • 規範的接口標準。  
  • 跨語言。

補充:服務器

  Restful是一種架構風格,關注的是資源。網絡

    經過每次http請求把資源拿過來,但資源怎麼用是客戶端的事情。架構

       gRpc是rpc的一個實現框架,所以關注其中的rpc遠程過程調用。框架

    意思是在客戶端調用服務器方法就像調用本地方法同樣。若是這樣作,那麼服務器就必需要有相應的處理的方法(參數和返回值)。dom

    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="Protos\Duplicate.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

相關文章
相關標籤/搜索