.NetCore gRpc 客户端与服务端的单工通信Demo

文章目录

  • .NetCore gRpc 客户端与服务端的单工通信Demo
    • 服务端
      • 方式一
      • 方式二
    • 客户端
    • proto协议文件
      • syntax = "proto3";
      • import "google/protobuf/empty.proto";
      • service
      • proto3与.netCore 的类型对应
      • 日期和时间
      • 可为 null 的类型
      • 字节
      • 小数
        • 为 Protobuf 创建自定义 decimal 类型
    • 集合
      • 列表
      • 字典
    • 无结构的条件消息
      • 任意
      • Oneof
      • “值”

.NetCore gRpc 客户端与服务端的单工通信Demo

服务端

方式一

使用vs 2022(也可以是其他版本)创建一个grpc的服务,如下这样

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uipEG9Xu-1687172462785)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230619183828284.png)]

简单方便,创建项目后的目录结构如下图

  • Protos:协议目录,里面是grpc的协议文件 默认是greet.proto
  • Services:服务目录,对服务功能进行重写,默认文件是 GreeterService.cs

方式二

  • 新建一个控制台程序,引入nuget包(版本根据实际情况确定)

  • 新建一个Protos目录(当然也可以是其他的),新建一个文本文件命名为xxxxx.proto

  • 编辑xxxx.proto文件(具体格式下面介绍)

  • 鼠标右键项目,添加–>服务引用–>gRPC–>选择文件(刚刚的那个proto文件)–>生成类型选择服务器,如下图

在这里插入图片描述

  • 点击完成

  • 新建一个Service.cs类,继承自生成的类后,重写处理方法(如果没有生成就先编译一下工程文件)

      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){Console.WriteLine($"接收到请求!{request.Name}");return Task.FromResult(new HelloReply{Message = "Hello " + request.Name});}public override Task<Empty> SayBye(Empty request, ServerCallContext context){return base.SayBye(request, context);}}
    

    注意命名空间

客户端

  • 新建一个控制台

  • 添加引用服务 grpc,选择客户端(具体操作和上面的生成服务端的类似)

  • 代码如下

     internal class Program{static async Task Main(string[] args){Console.WriteLine("Hello, World!");var channel = GrpcChannel.ForAddress("https://localhost:6001"); var client = new Greeter.GreeterClient(channel);var response = await client.SayHelloAsync(new HelloRequest { Name = "张三 李四 王五" });Console.WriteLine(response.Message);}}
    

    运行两个程序就可以了。

proto协议文件

https://developers.google.com/protocol-buffers/docs/proto

上面的连接有详细说明,下面简单介绍一些基本使用

syntax = "proto3";import "google/protobuf/empty.proto";option csharp_namespace = "Demo_WarningMonitor.OpcUA.Client";package greet;// The greeting service definition.
service Greeter {// Sends a greetingrpc SayHello (HelloRequest) returns (HelloReply);rpc SayBye(google.protobuf.Empty) returns (google.protobuf.Empty);
}// The request message containing the user's name.
message HelloRequest {string name = 1;
}// The response message containing the greetings.
message HelloReply {string message = 1;
}

syntax = “proto3”;

声明协议语法是proto3

import “google/protobuf/empty.proto”;

导入一些默认的类型

service

定义一个服务,内部使用rpc关键字指定方法描述

proto3与.netCore 的类型对应

Protobuf 支持一系列本机标量值类型。 下表列出了全部本机标量值类型及其等效 C# 类型:

Protobuf 类型C# 类型
doubledouble
floatfloat
int32int
int64long
uint32uint
uint64ulong
sint32int
sint64long
fixed32uint
fixed64ulong
sfixed32int
sfixed64long
boolbool
stringstring
bytesByteString

标量值始终具有默认值,并且该默认值不能设置为 null。 此约束包括 stringByteString,它们都属于 C# 类。 string 默认为空字符串值,ByteString 默认为空字节值。 尝试将它们设置为 null 会引发错误。

可为 null 的包装器类型可用于支持 null 值。

日期和时间

本机标量类型不提供与 .NET 的 DateTimeOffset、DateTime 和 TimeSpan 等效的日期和时间值。 可使用 Protobuf 的一些“已知类型”扩展来指定这些类型。 这些扩展为受支持平台中的复杂字段类型提供代码生成和运行时支持。

下表显示日期和时间类型:

.NET 类型Protobuf 已知类型
DateTimeOffsetgoogle.protobuf.Timestamp
DateTimegoogle.protobuf.Timestamp
TimeSpangoogle.protobuf.Duration

ProtoBuf复制

syntax = "proto3";import "google/protobuf/duration.proto";  
import "google/protobuf/timestamp.proto";message Meeting {string subject = 1;google.protobuf.Timestamp start = 2;google.protobuf.Duration duration = 3;
}  

可为 null 的类型

C# 的 Protobuf 代码生成使用本机类型,如 int 表示 int32。 因此这些值始终包括在内,不能为 null

对于需要显式 null 的值(例如在 C# 代码中使用 int?),Protobuf 的“已知类型”包括编译为可以为 null 的 C# 类型的包装器。 若要使用它们,请将 wrappers.proto 导入到 .proto 文件中,如以下代码所示:

ProtoBuf复制

syntax = "proto3";import "google/protobuf/wrappers.proto";message Person {// ...google.protobuf.Int32Value age = 5;
}

wrappers.proto 类型不会在生成的属性中公开。 Protobuf 会自动将它们映射到 C# 消息中相应的可为 null 的 .NET 类型。 例如,google.protobuf.Int32Value 字段生成 int? 属性。 引用类型属性(如 stringByteString )保持不变,但可以向它们分配 null,这不会引发错误。

下表完整列出了包装器类型以及它们的等效 C# 类型:

C# 类型已知类型包装器
bool?google.protobuf.BoolValue
double?google.protobuf.DoubleValue
float?google.protobuf.FloatValue
int?google.protobuf.Int32Value
long?google.protobuf.Int64Value
uint?google.protobuf.UInt32Value
ulong?google.protobuf.UInt64Value
stringgoogle.protobuf.StringValue
ByteStringgoogle.protobuf.BytesValue

字节

Protobuf 支持标量值类型为 bytes 的二进制有效负载。 C# 中生成的属性使用 ByteString 作为属性类型。

使用 ByteString.CopyFrom(byte[] data) 从字节数组创建新实例:

var data = await File.ReadAllBytesAsync(path);var payload = new PayloadResponse();
payload.Data = ByteString.CopyFrom(data);

使用 ByteString.SpanByteString.Memory 直接访问 ByteString 数据。 或调用 ByteString.ToByteArray() 将实例转换回字节数组:

var payload = await client.GetPayload(new PayloadRequest());await File.WriteAllBytesAsync(path, payload.Data.ToByteArray());

小数

Protobuf 本身不支持 .NET decimal 类型,只支持 doublefloat。 在 Protobuf 项目中,我们正在探讨这样一种可能性:将标准 decimal 类型添加到已知类型,并为支持它的语言和框架添加平台支持。 尚未实现任何内容。

可以创建消息定义来表示 decimal 类型,以便在 .NET 客户端和服务器之间实现安全序列化。 但其他平台上的开发人员必须了解所使用的格式,并能够实现自己对其的处理。

为 Protobuf 创建自定义 decimal 类型

ProtoBuf复制

package CustomTypes;// Example: 12345.6789 -> { units = 12345, nanos = 678900000 }
message DecimalValue {// Whole units part of the amountint64 units = 1;// Nano units of the amount (10^-9)// Must be same sign as unitssfixed32 nanos = 2;
}

nanos 字段表示从 0.999_999_999-0.999_999_999 的值。 例如,decimal1.5m 将表示为 { units = 1, nanos = 500_000_000 }。 这就是此示例中的 nanos 字段使用 sfixed32 类型的原因:对于较大的值,其编码效率比 int32 更高。 如果 units 字段为负,则 nanos 字段也应为负。

集合

列表

Protobuf 中,在字段上使用 repeated 前缀关键字指定列表。 以下示例演示如何创建列表:

message Person {// ...repeated string roles = 8;
}

在生成的代码中,repeated 字段由 Google.Protobuf.Collections.RepeatedField<T> 泛型类型表示。

public class Person
{// ...public RepeatedField<string> Roles { get; }
}

RepeatedField<T> 可实现 IList。 因此你可使用 LINQ 查询,或者将其转换为数组或列表。 RepeatedField<T> 属性没有公共 setter。 项应添加到现有集合中。

var person = new Person();// Add one item.
person.Roles.Add("user");// Add all items from another collection.
var roles = new [] { "admin", "manager" };
person.Roles.Add(roles);

字典

.NET IDictionary 类型在 Protobuf 中使用 map<key_type, value_type> 表示。

message Person {// ...map<string, string> attributes = 9;
}

在生成的 .NET 代码中,map 字段由 Google.Protobuf.Collections.MapField<TKey, TValue> 泛型类型表示。 MapField<TKey, TValue> 可实现 IDictionary。 与 repeated 属性一样,map 属性没有公共 setter。 项应添加到现有集合中。

var person = new Person();// Add one item.
person.Attributes["created_by"] = "James";// Add all items from another collection.
var attributes = new Dictionary<string, string>
{["last_modified"] = DateTime.UtcNow.ToString()
};
person.Attributes.Add(attributes);

无结构的条件消息

Protobuf 是一种协定优先的消息传递格式。 构建应用时,必须在 .proto 文件中指定应用的消息,包括其字段和类型。 Protobuf 的协定优先设计非常适合强制执行消息内容,但可能会限制不需要严格协定的情况:

  • 包含未知有效负载的消息。 例如,具有可以包含任何消息的字段的消息。
  • 条件消息。 例如,从 gRPC 服务返回的消息可能是成功结果或错误结果。
  • 动态值。 例如,具有包含非结构化值集合的字段的消息,类似于 JSON。

Protobuf 提供语言功能和类型来支持这些情况。

任意

利用 Any 类型,可以将消息作为嵌入类型使用,而无需 .proto 定义。 若要使用 Any 类型,请导入 any.proto

import "google/protobuf/any.proto";message Status {string message = 1;google.protobuf.Any detail = 2;
}
// Create a status with a Person message set to detail.
var status = new ErrorStatus();
status.Detail = Any.Pack(new Person { FirstName = "James" });// Read Person message from detail.
if (status.Detail.Is(Person.Descriptor))
{var person = status.Detail.Unpack<Person>();// ...
}

Oneof

oneof 字段是一种语言特性。 编译器在生成消息类时处理 oneof 关键字。 使用 oneof 指定可能返回 PersonError 的响应消息可能如下所示:

message Person {// ...
}message Error {// ...
}message ResponseMessage {oneof result {Error error = 1;Person person = 2;}
}

在整个消息声明中,oneof 集内的字段必须具有唯一的字段编号。

使用 oneof 时,生成的 C# 代码包括一个枚举,用于指定哪些字段已设置。 可以测试枚举来查找已设置的字段。 未设置的字段将返回 null 或默认值,而不是引发异常。

var response = await client.GetPersonAsync(new RequestMessage());switch (response.ResultCase)
{case ResponseMessage.ResultOneofCase.Person:HandlePerson(response.Person);break;case ResponseMessage.ResultOneofCase.Error:HandleError(response.Error);break;default:throw new ArgumentException("Unexpected result.");
}

“值”

Value 类型表示动态类型的值。 它可以是 null、数字、字符串、布尔值、值字典 (Struct) 或值列表 (ValueList)。 Value 是一个 Protobuf 已知类型,它使用前面讨论的 oneof 功能。 若要使用 Value 类型,请导入 struct.proto

import "google/protobuf/struct.proto";message Status {// ...google.protobuf.Value data = 3;
}
// Create dynamic values.
var status = new Status();
status.Data = Value.ForStruct(new Struct
{Fields ={["enabled"] = Value.ForBool(true),["metadata"] = Value.ForList(Value.ForString("value1"),Value.ForString("value2"))}
});// Read dynamic values.
switch (status.Data.KindCase)
{case Value.KindOneofCase.StructValue:foreach (var field in status.Data.StructValue.Fields){// Read struct fields...}break;// ...
}

直接使用 Value 可能很冗长。 使用 Value 的替代方法是通过 Protobuf 的内置支持,将消息映射到 JSON。 Protobuf 的 JsonFormatterJsonWriter 类型可用于任何 Protobuf 消息。 Value 特别适用于与 JSON 进行转换。

以下是与之前的代码等效的 JSON:

// Create dynamic values from JSON.
var status = new Status();
status.Data = Value.Parser.ParseJson(@"{""enabled"": true,""metadata"": [ ""value1"", ""value2"" ]
}");// Convert dynamic values to JSON.
// JSON can be read with a library like System.Text.Json or Newtonsoft.Json
var json = JsonFormatter.Default.Format(status.Data);
var document = JsonDocument.Parse(json);

https://learn.microsoft.com/zh-cn/dotnet/architecture/grpc-for-wcf-developers/migrate-duplex-services

https://learn.microsoft.com/zh-cn/aspnet/core/grpc/protobuf?view=aspnetcore-7.0

https://blog.csdn.net/iml6yu/article/details/102948188?ops_request_misc=&request_id=45879ab70342436ea16723b29630d5e4&biz_id=&utm_medium=distribute.pc_search_result.none-task-blog-2blogkoosearch~default-1-102948188-null-null.268v1control&utm_term=Grpc&spm=1018.2226.3001.4450

https://blog.csdn.net/iml6yu/article/details/102959674?ops_request_misc=&request_id=45879ab70342436ea16723b29630d5e4&biz_id=&utm_medium=distribute.pc_search_result.none-task-blog-2blogkoosearch~default-2-102959674-null-null.268v1control&utm_term=Grpc&spm=1018.2226.3001.4450

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/8880.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

echarts飘警告[ECharts] There is a chart instance already initialized on the dom.

if (//判断是否存在echarts实例化对象,如果存在则销毁this.myChart ! null &&this.myChart ! &&this.myChart ! undefined ) {this.myChart.dispose() } var chartDom this.$refs.chartName this.myChart echarts.init(chartDom)

MIT6.584分布式-原MIT6.824-lab1-2023年万字从0到1小白学习笔记

文章目录 前置准备一、分布式系统知识的学习1.1分布式Go语言环境安装1.2MIT6.824课程的学习1.2* 前言学习 可以看到这个任务是不会完成的&#xff0c;在我们没有开始进行编码的时候1.3课程需求1.4怎么实现、借助课程的Hints1.5首先看看其mapfunction的工作逻辑&#xff1a; 二、…

r‘./csv‘和f‘./csv‘有啥区别

r./csv 和 f./csv 在文件路径中具有不同的含义和用途。 r./csv&#xff1a;这是使用原始字符串&#xff08;raw string&#xff09;表示法来表示文件路径。在原始字符串中&#xff0c;反斜杠字符&#xff08;\&#xff09;不会被视为转义字符&#xff0c;而是作为普通字符。因…

centos7安装zookeeper的环境变量配置导致用户登录不了系统

废话不多说&#xff0c;我修改的/etc/profile,如果这个文件改错会造成所有用户都登录不了系统。 第一步&#xff1a;解决进不了系统 1.在登陆界面按&#xff1a;alt ctrlf2进入命令模式&#xff0c;输入密码登录后再输入&#xff1a; /usr/bin/sudo /usr/bin/vi /etc/profile …

在选择自动化测试工具时需要考虑哪些因素?

自动化测试工具是软件开发中不可或缺的一部分&#xff0c;它可以提高测试效率、减少人力成本、提升软件质量&#xff0c;那在选择自动化测试工具时需要考虑哪些因素&#xff1f; 测试需求&#xff1a;首先要明确自动化测试的需求是什么&#xff0c;不同的测试需求对应着不同的工…

学习vue2笔记

学习vue2笔记 文章目录 学习vue2笔记脚手架文件结构关于不同版本的Vuevue.config.js配置文件ref属性props配置项mixin(混入)插件scoped样式总结TodoList案例webStorage组件的自定义事件全局事件总线&#xff08;GlobalEventBus&#xff09;消息订阅与发布&#xff08;pubsub&am…

两台电脑之间传输文件——就近共享

文章目录 背景步骤补充&#xff1a;跨设备共享 背景 两台电脑之间共享文件有很多种方式&#xff0c;这里介绍一种最简洁的——Windows自带的就近共享。它适合偶尔传输一些简单文件。比如把笔记本上的电子书传输到surface上阅读。 注意: 如果共享的电脑正在运行最新版本的Wind…

如何使用Scrum工具进行敏捷项目管理?

敏捷开发是一种轻量级的软件开发方式。 敏捷是一种通过创造变化和响应变化在不确定和混乱的环境中取得成功的能力。 敏捷开发是为了快速响应市场变化、通过自组织、跨职能团队 运用适合他们自身环境的实践进行演进得出解决方案。 所有符合敏捷宣言和敏捷开发十二项原则的方…

SNMP 计算机网络管理 实验2(三) SNMP服务与常用网管命令之任务五:查看端口流量及实验小结

⬜⬜⬜ &#x1f430;&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;(*^▽^*)欢迎光临 &#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;&#x1f430;⬜⬜⬜ ✏️write in front✏️ &#x1f4dd;个人主页&#xff1a;陈丹宇jmu &am…

[SpringBoot]单点登录

关于单点登录 单点登录的基本实现思想&#xff1a; 当客户端提交登录请求时&#xff0c;服务器端在验证登录成功后&#xff0c;将生成此用户对应的JWT数据&#xff0c;并响应到客户端 客户端在后续的访问中&#xff0c;将自行携带JWT数据发起请求&#xff0c;通常&#xff0c…

Qt和MySQL的连接

具体视频的教程 视频教程 我的文章是做一下补充的 流程&#xff1a; 第一点你要确保你的数据库的位数&#xff0c;如果你数据库位数的是32位&#xff0c;mingw编译的时候就需要选择的是32位**&#xff08;在下面会提到&#xff09;** 去到所在的文件 点击.pro文件进行编译…

React | 再战Redux

✨ 个人主页&#xff1a;CoderHing &#x1f5a5;️ React.js专栏&#xff1a;React.js 再战Redux &#x1f64b;‍♂️ 个人简介&#xff1a;一个不甘平庸的平凡人&#x1f36c; &#x1f4ab; 系列专栏&#xff1a;吊打面试官系列 16天学会Vue 7天学会微信小程序 Node专栏…