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 The RPC Service Definition

客户端与服务端使用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文件,了解protocol buffers的基本语法

从.proto文件上大致知道 定义的服务功能 (给某人一个回应), 这里提示一些语法:

  1. syntax指示使用的protocol buffers的版本。在这种情况下,proto3是撰写本文时的最新版本。
  2. csharp_namespace指示生成的文件所在的命名空间package说明符也是这个作用,用于防止协议消息类型之间的名称冲突。

对于C#,如果提供选项csharp_namespace,csharp_namespace值将用作命名空间;

在Java中,如果提供选项java_package,java_package将用作包名称。

  1. service Greeter定义服务基类名称, rpc SayHello (HelloRequest) returns (HelloReply); 是一个一元rpc调用
  2. HelloRequestHelloReply是在客户端和服务器之间交换信息的数据结构。它们被称为消息

    你在消息字段中定义的数字是不可重复的,当消息被序列化为Protobuf时,该数字用于标识字段,这是因为序列化一个数字比序列化整个字段名称要快。
  3. 更多语法,请查看https://developers.google.com/protocol-buffers/docs/overview

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文件进行编译。

  1. 拷贝服务端项目中的..proto文件
  2. 将选项csharp_namespace值修改为GrpcAuthorClient。
  3. 更新.csproj文件的配置节
<ItemGroup>
<Protobuf Include="Protos\author.proto" GrpcServices="Client" />
</ItemGroup>
  1. 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. 其他核心功能

1. 通信方式
  • Unary RPC(一元Rpc调用): 上面的例子
  • Server streaming RPC : 服务器流式RPC,客户端在其中向服务器发送请求,并获取流以读取回一系列消息。客户端从返回的流中读取,直到没有更多消息为止。 gRPC保证单个RPC调用中的消息顺序。
  • Client streaming RPC:客户端流式RPC,客户端在其中编写一系列消息,然后再次使用提供的流将它们发送到服务器。客户端写完消息后,它将等待服务器读取消息并返回响应。同样,gRPC保证了单个RPC调用中的消息顺序
  • Bidirectional streaming RPC: 双向流式RPC,双方都使用读写流发送一系列消息。这两个流是独立运行的,因此客户端和服务器可以按照自己喜欢的顺序进行读写:例如,服务器可以在写响应之前等待接收所有客户端消息,或者可以先读取一条消息再写入一条消息,或读写的其他组合。每个流中的消息顺序都会保留。
2. Metadata

元数据是以键值对列表的形式提供的有关特定RPC调用的信息(例如身份验证详细信息),其中键是字符串,值通常是字符串,但可以是二进制数据。

元数据对于gRPC本身是不透明的:它允许客户端向服务器提供与调用相关的信息,反之亦然。

3. Channels

gRPC通道提供到指定主机和端口上的gRPC服务器的连接。

创建客户端存根时用到它,可以指定通道参数来修改gRPC的默认行为,例如打开或关闭消息压缩。

通道具有状态,包括已连接和空闲。


4 gRPC打乒乓球

针对脚手架项目,稍作修改--->乒乓球局

(考察gRpc双向流式通信、Timeout机制、异常处理):

客户端发送"gridsum", 服务端回发"musdirg"; 客户端再发送"gridsum", 往复......

① 添加接口

rpc PingPongHello(stream HelloRequest) returns (stream HelloReply);

② 实现服务契约

 public override async Task PingPongHello(IAsyncStreamReader<HelloRequest> requestStream,IServerStreamWriter<HelloReply> responseStream, ServerCallContext context)
{
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}");
}
catch (IOException ex)
{
System.Diagnostics.Debug.WriteLine($"{ex.Message}");
}
}

③ 添加客户端代码

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(版本3)定义服务接口以及如何使用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 核心功能初体验,附Demo源码的更多相关文章

  1. winserver的consul部署实践与.net core客户端使用(附demo源码)

    winserver的consul部署实践与.net core客户端使用(附demo源码)   前言 随着微服务兴起,服务的管理显得极其重要.都知道微服务就是”拆“,把臃肿的单块应用,拆分成多个轻量级的 ...

  2. Asp.net MVC集成Google Calendar API(附Demo源码)

    Asp.net MVC集成Google Calendar API(附Demo源码) Google Calendar是非常方便的日程管理应用,很多人都非常熟悉.Google的应用在国内不稳定,但是在国外 ...

  3. Android Studio 的蓝牙串口通信(附Demo源码下载)

    根据相关代码制作了一个开源依赖包,将以下所有的代码进行打包,直接调用即可完成所有的操作.详细说明地址如下,如果觉得有用可以GIthub点个Star支持一下: 项目官网 Kotlin版本说明文档 Jav ...

  4. 物流一站式单号查询之快递鸟API接口(附Demo源码)

    连载篇提前看 物流一站式单号查询之快递鸟API接口 物流一站式查询之TrackingMore篇 物流一站式查询之顺丰接口篇 物流一站式查询之快递100 前情提要 前三篇中,我们已经从注册.申请接口.调 ...

  5. Android 二维码 生成和识别(附Demo源码)

    今天讲一下目前移动领域很常用的技术——二维码.现在大街小巷.各大网站都有二维码的踪迹,不管是IOS. Android.WP都有相关支持的软件.之前我就想了解二维码是如何工作,最近因为工作需要使用相关技 ...

  6. 【转】Android 二维码 生成和识别(附Demo源码)--不错

    原文网址:http://www.cnblogs.com/mythou/p/3280023.html 今天讲一下目前移动领域很常用的技术——二维码.现在大街小巷.各大网站都有二维码的踪迹,不管是IOS. ...

  7. .NET WebSockets 核心原理初体验

    上个月我写了<.NET gRPC核心功能初体验>, 里面使用gRPC双向流做了一个打乒乓球的Demo, 实时双向这两个标签是不是很熟悉,对, WebSockets也可以做实时双向通信. 本 ...

  8. ASP.NET Core 3.0 上的gRPC服务模板初体验(多图)

    早就听说ASP.NET Core 3.0中引入了gRPC的服务模板,正好趁着家里电脑刚做了新系统,然后装了VS2019的功夫来体验一把.同时记录体验的过程.如果你也想按照本文的步骤体验的话,那你得先安 ...

  9. 实现类似QQ自拍头像的功能(demo源码)

    在很多软件系统中,都允许用户设置自己的头像,甚至可以直接使用摄像头照相作为自己的头像,就像QQ的自拍头像功能一样. 这种功能是如何实现的了?最直接的,我们可以使用Windows提供的VFW技术或Dir ...

随机推荐

  1. DDD领域驱动设计:CQRS

    1 前置阅读 在阅读本文章之前,你可以先阅读: DDD领域驱动设计是什么 DDD领域驱动设计:实体.值对象.聚合根 DDD领域驱动设计:仓储 MediatR一个优秀的.NET中介者框架 2 什么是CQ ...

  2. idea中类注释和方法注释的设置

    类注释设置 近几年版本的idea在设置类名时从Includes中引用文件,所以只需要在被引用的文件中设置对应注释即可. /** *@className: ${NAME} *@description: ...

  3. 狂神说SpringBoot11:Thymeleaf模板引擎

    狂神说SpringBoot系列连载课程,通俗易懂,基于SpringBoot2.2.5版本,欢迎各位狂粉转发关注学习. 微信公众号:狂神说(首发)    Bilibili:狂神说Java(视频) 未经作 ...

  4. Hiho1422 Harmonic Matrix Counter (高斯消元)

    16年北京站A题 真的难啊.. 题意: 定义和谐矩阵 就是每个元素和上下左右的xor值=0 输出一个超大数 然后最多800个询问 求字典序第k小的和谐矩阵 x y位置上的数 题解: 首先这个超大数的范 ...

  5. Codeforces Round #604 (Div. 2) C. Beautiful Regional Contest(贪心)

    题目链接:https://codeforces.com/contest/1265/problem/C 题意 从大到小给出 $n$ 只队伍的过题数,要颁发 $g$ 枚金牌,$s$ 枚银牌,$b$ 枚铜牌 ...

  6. hdu 6814 Tetrahedron 规律+排列组合逆元

    题意: 给你一个n,你需要从1到n(闭区间)中选出来三个数a,b,c(可以a=b=c),用它们构成一个直角四面体的三条棱(可看图),问你从D点到下面的三角形做一条垂线h,问你1/h2的期望 题解: 那 ...

  7. Codeforces Round #690 (Div. 3) E2. Close Tuples (hard version) (数学,组合数)

    题意:给你一长度为\(n\)的序列(可能含有相等元素),你要找到\(m\)个位置不同的元素使得\(max(a_{i-1},a_{i_2},...,a_{i_m})-min(a_{i-1},a_{i_2 ...

  8. hdu4770 Lights Against Dudely

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission ...

  9. Codeforces Round #681 (Div. 2, based on VK Cup 2019-2020 - Final) D. Extreme Subtraction (贪心)

    题意:有一个长度为\(n\)的序列,可以任意取\(k(1\le k\le n)\),对序列前\(k\)项或者后\(k\)减\(1\),可以进行任意次操作,问是否可以使所有元素都变成\(0\). 题解: ...

  10. URAL - 1635 哈希区间(或者不哈希)+dp

    题意: 演队在口试中非常不幸.在42道考题中,他恰好没有准备最后一道题,而刚好被问到的正是那道题.演队坐在教授面前,一句话也说不出来.但教授心情很好,给了演队最后一次通过考试的机会.他让这个可怜的学生 ...