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="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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM