.NET gRPC核心功能初体验

简介: gRPC是高性能的RPC框架, 有效地用于服务通信(不管是数据中心内部还是跨数据中心)。

由Google开源,目前是一个Cloud Native Computing Foundation(CNCF)孵化项目。

其功能包括:


双向流

强大的二进制序列化

可插拔的身份验证,负载平衡和运行状况检查


613df536094bafe2e2ae5ce9597a8449.png


在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 greeting  rpc 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调用    


HelloRequestHelloReply是在客户端和服务器之间交换信息的数据结构。它们被称为消息


你在消息字段中定义的数字是不可重复的,当消息被序列化为Protobuf时,该数字用于标识字段,这是因为序列化一个数字比序列化整个字段名称要快。


1.2 实现服务接口


    为了从.proto文件生成代码,可以使用protoc编译器和C#插件来生成服务器或客户端代码。


脚手架项目使用Grpc.AspNetCore NuGet包:所需的类由构建过程自动生成, 你只需要在项目.csproj文件中添加配置节:


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


生成的代码知道如何使用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连接)");       } }


          82411da98bb2a10a0e3d4465d0eb8f36.jpg


          https://github.com/zaozaoniao/GrpcAuthor


          总结


          gRPC是具有可插拔身份验证和负载平衡功能的高性能RPC框架。


          使用protocol buffers定义结构化数据;使用不同语言自动产生的源代码在各种数据流中写入和读取结构化数据。


          在本文中,您学习了如何使用protocol buffers 定义服务接口以及如何使用C#实现服务。最后,您使用gRPC双向流式通信创建了 "打乒乓球"Demo。

          相关文章
          |
          4月前
          |
          人工智能 开发框架 .NET
          .NET技术的强大功能:.NET技术的基础特性、在现代开发中的应用、以及它如何助力未来的软件开发。
          .NET技术是软件开发领域的核心支柱,以其强大功能、灵活性及安全性广受认可。本文分三部分解析:基础特性如多语言支持、统一运行时环境;现代应用如企业级与Web开发、移动应用、云服务及游戏开发;以及未来趋势如性能优化、容器化、AI集成等,展望.NET在不断变化的技术环境中持续发展与创新。
          137 4
          |
          1月前
          |
          开发框架 .NET C#
          在 ASP.NET Core 中创建 gRPC 客户端和服务器
          本文介绍了如何使用 gRPC 框架搭建一个简单的“Hello World”示例。首先创建了一个名为 GrpcDemo 的解决方案,其中包含一个 gRPC 服务端项目 GrpcServer 和一个客户端项目 GrpcClient。服务端通过定义 `greeter.proto` 文件中的服务和消息类型,实现了一个简单的问候服务 `GreeterService`。客户端则通过 gRPC 客户端库连接到服务端并调用其 `SayHello` 方法,展示了 gRPC 在 C# 中的基本使用方法。
          42 5
          在 ASP.NET Core 中创建 gRPC 客户端和服务器
          |
          1天前
          |
          网络协议 C#
          3款.NET开源、功能强大的通讯调试工具,效率提升利器!
          3款.NET开源、功能强大的通讯调试工具,效率提升利器!
          21 10
          |
          1月前
          |
          消息中间件 监控 数据可视化
          基于.NET开源、功能强大且灵活的工作流引擎框架
          基于.NET开源、功能强大且灵活的工作流引擎框架
          |
          1月前
          |
          XML 开发框架 .NET
          .NET 9 中 LINQ 新增功能实操
          .NET 9 中 LINQ 新增功能实操
          |
          1月前
          |
          网络协议 Unix Linux
          精选2款C#/.NET开源且功能强大的网络通信框架
          精选2款C#/.NET开源且功能强大的网络通信框架
          |
          1月前
          |
          开发框架 JavaScript 前端开发
          2024年全面且功能强大的.NET快速开发框架推荐,效率提升利器!
          2024年全面且功能强大的.NET快速开发框架推荐,效率提升利器!
          |
          1月前
          |
          网络协议 网络安全 Apache
          一个整合性、功能丰富的.NET网络通信框架
          一个整合性、功能丰富的.NET网络通信框架
          |
          1月前
          |
          消息中间件 开发框架 .NET
          .NET 8 强大功能 IHostedService 与 BackgroundService 实战
          【11月更文挑战第7天】本文介绍了 ASP.NET Core 中的 `IHostedService` 和 `BackgroundService` 接口及其用途。`IHostedService` 定义了 `StartAsync` 和 `StopAsync` 方法,用于在应用启动和停止时执行异步操作,适用于资源初始化和清理等任务。`BackgroundService` 是 `IHostedService` 的抽象实现,简化了后台任务的编写,通过 `ExecuteAsync` 方法实现长时间运行的任务逻辑。文章还提供了创建和注册这两个服务的实战步骤,帮助开发者在实际项目中应用这些功能。
          |
          2月前
          .NET 4.0下实现.NET4.5的Task类相似功能组件
          【10月更文挑战第29天】在.NET 4.0 环境下,可以使用 `BackgroundWorker` 类来实现类似于 .NET 4.5 中 `Task` 类的功能。`BackgroundWorker` 允许在后台执行耗时操作,同时不会阻塞用户界面线程,并支持进度报告和取消操作。尽管它有一些局限性,如复杂的事件处理模型和不灵活的任务管理方式,但在某些情况下仍能有效替代 `Task` 类。