.NET gRPC核心功能初体验
? ? gRPC是高性能的RPC框架, 有效地用于服務通信(不管是數據中心內部還是跨數據中心)。
由Google開源,目前是一個Cloud Native Computing Foundation(CNCF)孵化項目。
其功能包括:
?雙向流?強大的二進制序列化?可插拔的身份驗證,負載平衡和運行狀況檢查
在gRPC中,客戶端應用程序可以直接在A服務器上調用B服務器的方法,就好像它是本地對象一樣,從而使您更輕松地創建分布式應用程序和微服務。
與許多RPC系統一樣,gRPC也是圍繞著定義服務的思想(定義可遠程調用方法的入參和返回值類型)。
在服務端,服務端實現此接口并運行gRPC服務器,以處理客戶端調用。
在客戶端,客戶端有一個存根,提供與服務器相同的方法。
在本文中,我將向您展示如何使用.NET5創建gRPC服務。我將分解gRPC的一些重要基礎概念,并給出一個有意思的包羅核心功能的實例。
1.創建一個gRPC服務器
我們從gRPC服務模板創建一個新的dotnet項目。
如果使用Visual Studio,請創建一個新項目,然后選擇gRPC Service模板,使用GrpcAuthor作為項目的名稱。
1.1? 定義Rpc 服務
客戶端與服務端使用protocol buffers交流/通信:
protocol buffers既用作服務的接口定義語言(IDL),又用作底層消息交換格式。
① 使用protocol buffers在.proto文件中定義服務接口。在其中,定義可遠程調用的方法的入參和返回值類型,服務端實現此接口并運行gRPC服務器以處理客戶端調用。
② 定義服務后,使用protocol buffers編譯器protoc從.proto文件生成數據訪問/傳輸類,該文件包含服務接口中消息和方法的實現。
關注VS腳手架項目Protos文件夾中的greet.proto。
syntax = "proto3"; option csharp_namespace = "GrpcAuthor"; package greet; // The greeting service definition. service Greeter {// Sends a greetingrpc SayHello (HelloRequest) returns (HelloReply); } // The request message containing the user's name. message HelloRequest {string name = 1; } // The response message containing the greetings. message HelloReply {string message = 1; }從.proto文件內容上大致知道服務功能 (給某人一個回應), 這里提示一些語法:
①syntax指示使用的protocol buffers的版本。在這種情況下,proto3是撰寫本文時的最新版本。②csharp_namespace指示生成的文件所在的命名空間。package說明符也是這個作用,用于防止協議消息類型之間的名稱沖突。
對于C#,如果提供選項csharp_namespace,csharp_namespace值將用作命名空間;在Java中,如果提供選項java_package,java_package將用作包名稱。
? ? ③service Greeter定義服務基類名稱, rpc SayHello (HelloRequest) returns (HelloReply); 是一個一元rpc調用? ? ④HelloRequest和HelloReply是在客戶端和服務器之間交換信息的數據結構。它們被稱為消息。
你在消息字段中定義的數字是不可重復的,當消息被序列化為Protobuf時,該數字用于標識字段,這是因為序列化一個數字比序列化整個字段名稱要快。
1.2 實現服務接口
? ? ?為了從.proto文件生成代碼,可以使用protoc編譯器和C#插件來生成服務器或客戶端代碼。
腳手架項目使用Grpc.AspNetCore?NuGet包:所需的類由構建過程自動生成, 你只需要在項目.csproj文件中添加配置節:
生成的代碼知道如何使用protocol buffers與其他服務/客戶端進行通信。
C#工具生成GreeterBase類型,將用作實現gRPC服務的基類。
public class GreeterService : Greeter.GreeterBase {private readonly ILogger<GreeterService> _logger;public GreeterService(ILogger<GreeterService> logger){_logger = logger;}public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context){return Task.FromResult(new HelloReply{Message = "Hello " + request.Name});} }最后注冊Grpc端點endpoints.MapGrpcService<GreeterService >();
--- 啟動服務---...
2. 創建gRPC .NET控制臺客戶端
Visual Studio創建一個名為GrpcAuthorClient的新控制臺項目。
安裝如下nuget包:
Install-Package Grpc.Net.Client
Install-Package Google.Protobuf
Install-Package Grpc.Tools
Grpc.Net.Client包含.NET Core客戶端;
Google.Protobuf包含protobuf消息API;
Grpc.Tools對Protobuf文件進行編譯。
①拷貝服務端項目中的.proto文件②將選項csharp_namespace值修改為GrpcAuthorClient。③更新.csproj文件的配置節
<ItemGroup><Protobuf Include="Protos\greet.proto" GrpcServices="Client" /></ItemGroup>? ? ④Client主文件:
static void Main(string[] args) {var?serverAddress?=?"https://localhost:5001";using?var?channel?=?GrpcChannel.ForAddress(serverAddress);var client = new Greeter.GreeterClient(channel);var reply = client.SayHello(new HelloRequest { Name = "宋小寶!" });Console.WriteLine(reply.Message.ToString());Console.WriteLine("Press any key to exit...");Console.ReadKey(); }使用服務器地址創建GrpcChannel,使用GrpcChannel對象實例化GreeterClient;
然后使用SayHello同步方法; 打印服務器響應結果。
3. 其他核心功能
3.1??通信方式
Unary RPC(一元Rpc調用): 上面的例子
Server streaming RPC :服務器流式RPC,客戶端在其中向服務器發送請求,并讀取消息流。客戶端從返回的流中讀取,直到沒有更多消息為止。gRPC保證單個RPC調用中的消息順序。
Client streaming RPC:客戶端流式RPC,客戶端使用流,寫入一系列消息并發送到服務器。客戶端寫完消息后,它將等待服務器讀取消息并返回響應。同樣,gRPC保證了單個RPC調用中的消息順序。
Bidirectional streaming RPC:雙向流式通信,由于兩個流是獨立的,因此客戶端和服務器可以按任何順序讀取和寫入消息。例如,服務器可以等到收到客戶端的所有消息后再寫消息,或者服務器和客戶端可以打“乒乓” (服務器收到請求,然后響應消息,然后客戶端基于響應發送另一個消息,依此往返)
3.2?Metadata
? ? ? ?元數據是以鍵值對列表的形式提供的有關特定RPC調用的信息(例如身份驗證詳細信息),其中鍵是字符串,值通常是字符串,但可以是二進制數據。元數據對于gRPC本身是不透明的:它允許客戶端向服務器提供與調用相關的信息,反之亦然。
3.3??Channels
? ? ? ? gRPC通道提供到指定主機和端口上的gRPC服務器的連接。
創建客戶端存根時用到它,可以指定通道參數來修改gRPC的默認行為,例如打開或關閉消息壓縮。
通道具有狀態,包括已連接和空閑。
4. gRpc打乒乓球
針對腳手架項目,稍作修改--->乒乓球局
(考察gRpc雙向流式通信、Timeout機制、異常處理):??
客戶端發送"gridsum",? 服務端回發"musdirg";? 客戶端再發送"gridsum", 往復......
① 添加接口
rpc PingPongHello(stream HelloRequest) returns (stream HelloReply);② 實現服務契約
try {while (!context.CancellationToken.IsCancellationRequested){var asyncRequests = requestStream.ReadAllAsync();// 客戶端與服務端"打乒乓"await foreach (var req in asyncRequests){var?send?=?Reverse(req.Name);await responseStream.WriteAsync(new HelloReply{Message = send,Id = req.Id +1});Debug.WriteLine($"第{req.Id}回合,服務端收到 {req.Name};開始第{req.Id + 1}回合,服務端回發 {send}");}} } catch(RpcException ex) {System.Diagnostics.Debug.WriteLine($"{ex.Message}"); }?③?客戶端代碼,控制乒乓球局在5s后終止
using (var cancellationTokenSource = new CancellationTokenSource( 5* 1000)) {try{var duplexMessage = client.PingPongHello(null, null, cancellationTokenSource.Token);await duplexMessage.RequestStream.WriteAsync(new HelloRequest { Id = 1, Name = "gridsum" }) ;var?asyncResp?=?duplexMessage.ResponseStream.ReadAllAsync();await foreach (var resp in asyncResp){var send = Reverse(resp.Message);await?duplexMessage.RequestStream.WriteAsync(new?HelloRequest?{Id=?resp.Id,?Name?=?send?});Console.WriteLine($"第{resp.Id}回合,客戶端收到 {resp.Message}, 客戶端發送{send}");}}catch?(RpcException?ex){Console.WriteLine("打乒乓球時間到了(客戶端5s后終斷gRpc連接)");}}https://github.com/zaozaoniao/GrpcAuthor
總結
? ? ?gRPC是具有可插拔身份驗證和負載平衡功能的高性能RPC框架。
使用protocol buffers定義結構化數據;使用不同語言自動產生的源代碼在各種數據流中寫入和讀取結構化數據。
在本文中,您學習了如何使用protocol buffers 定義服務接口以及如何使用C#實現服務。最后,您使用gRPC雙向流式通信創建了 "打乒乓球"Demo。
Additional Resources
???https://developers.google.com/protocol-buffers/docs/csharptutorial???https://www.grpc.io/docs/what-is-grpc/core-concepts/???https://docs.microsoft.com/en-us/dotnet/architecture/grpc-for-wcf-developers/why-grpc
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的.NET gRPC核心功能初体验的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C# 打印PDF文档的10种方法
- 下一篇: 如何在 ASP.Net Core 中使用