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

news2024/11/24 11:53:57

文章目录

  • .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 greeting
  rpc 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 amount
    int64 units = 1;

    // Nano units of the amount (10^-9)
    // Must be same sign as units
    sfixed32 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.coloradmin.cn/o/663431.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

<Linux开发>驱动开发 -Linux MISC 驱动

&#xff1c;Linux开发&#xff1e;驱动开发 -Linux MISC 驱动 交叉编译环境搭建&#xff1a; &#xff1c;Linux开发&#xff1e; linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下&#xff1a; &#xff1c;Linux开发&#xff1e; -之-系统移植 uboot移植过程详细记…

软考高级系统架构设计师(二) 基础知识之计算机组成与系统结构2

目录 总线 ​CISC与RISC 流水线技术 总线 练习题&#xff1a; CISC与RISC RISC(精简指令集计算机)和CISC(复杂指令集计算机)是当前CPU的两种架构. RISC与CICS的比较 1.RISC比CICS更能提高计算机运算速度&#xff1b;RISC寄存器多&#xff0c;就可以减少访存次数&#xff0c;…

生产环境Java应用服务内存泄漏分析与解决

有个生产环境CRM业务应用服务&#xff0c;情况有些奇怪&#xff0c;监控数据显示内存异常。内存使用率99.%多。通过生产监控看板发现&#xff0c;CRM内存超配或内存泄漏的现象&#xff0c;下面分析一下这个问题过程记录。 1、服务器硬件配置部署情况 生产服务器采用阿里云ECS…

【命令参数】MSBuild - 环境配置及常用命令参数

目录 环境配置 基本语法 参数指令 对各类程序的命令参数的掌握是软件工程师必修课之一&#xff0c;它是通往自动化、高效化开发测试的必经之路。对于MSBuild&#xff0c;我们可以借助它以一种轻量级的形式去完成对于项目又或解决方案的生成&#xff0c;而避开使用繁大的IDE进…

Linux系统之部署Etherpad文档编辑器

Linux系统之部署Etherpad文档编辑器 一、Etherpad介绍1.Etherpad简介2.Etherpad特点 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本3.3 检查系统是否安装Node.js 四、部署Node.js 环境4.1 下载Node.js安装包…

【吴恩达老师《机器学习》】课后习题3之【逻辑回归解决多分类】与【神经网络】笔记(代码注释详细)

本次习题所用到的数据&#xff0c;#数据集&#xff1a;ex3data1.mat&#xff0c;参数&#xff1a;ex3weights.mat。在文章开头&#xff0c;下载即可&#xff01; 逻辑回归解决多分类问题 二分类VS多分类 在机器学习中&#xff0c;分类是一种监督学习任务&#xff0c;其中我们…

从机缘到成就

机缘 在这1825天的创作之旅中&#xff0c;我收获了许多宝贵的机遇和经验。起初&#xff0c;我只是一个对技术有着浓厚兴趣的普通人&#xff0c;遇到了一个在eclipse导入工程后出现中文乱码的问题。而我决定将这个问题记录下来&#xff0c;并分享给其他可能遇到相同困扰的人们。…

数据库系统概述——第三章 关系数据库标准语言SQL(知识点复习+练习题)

&#x1f31f;博主&#xff1a;命运之光 &#x1f984;专栏&#xff1a;离散数学考前复习&#xff08;知识点题&#xff09; &#x1f353;专栏&#xff1a;概率论期末速成&#xff08;一套卷&#xff09; &#x1f433;专栏&#xff1a;数字电路考前复习 &#x1f99a;专栏&am…

Linux基础内容(23)—— 信号补充与多线程交接知识

Linux基础内容&#xff08;22&#xff09;—— 信号_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/130835485 目录 1.可重入函数 1.情况假设 2.volatile 3.SIGCHLD信号 1.SIGCHLD介绍 2.信号的确认 3.wait的处理 1.可重入函数 1.情况假设…

插件 - 通过SPI方式实现插件管理

文章目录 SPI概念基本原理使用步骤优点缺点Code真实使用场景案例JDBC(Java Database Connectivity)Servlet API日志框架SPI概念 SPI(Service Provider Interface)是Java提供的一种服务扩展机制,它允许应用程序在运行时动态加载和发现提供者(Providers),并与它们进行交…

Proteus仿真之UART通信(点亮LED灯)

1.UART通信简介&#xff1a;通用异步收发传输器UART(Universal Asynchronous Receiver/Transmitter)是负责处理数据总线和串口之间的串/并通信的设备。UART通信规定了数据帧的格式&#xff1a;起始位、数据位、校验位、停止位等。UART异步通信只需要通信双方设置好数据帧的格式…

房屋装修选择自装,如何寻找水电工人,比价并施工(水电阶段)

环境&#xff1a; 地点&#xff1a;杭州 装修类型&#xff1a;自装 面积&#xff1a;建面135平方 进度&#xff1a;水电阶段 问题描述&#xff1a; 房屋装修选择自装&#xff0c;如何寻找水电工人&#xff0c;比价并施工 解决方案&#xff1a; 一、了解水电相关知识 水…

Python3+RIDE+RobotFramework自动化测试框架搭建

Python2.7已于2020年1月1日开始停用&#xff0c;之前RF做自动化都是基于Python2的版本。 没办法&#xff0c;跟随时代的脚步&#xff0c;我们也不得不升级以应用新的控件与功能。 升级麻烦&#xff0c;直接全新安装。 一、Python安装 最新版Python下载地址&#xff1a;http…

Qt连接Access数据库

Qt自带有QODBC驱动&#xff08;封装了ODBC驱动接口&#xff09;&#xff0c;通过windows平台上提供的ODBC驱动访问支持ODBC的数据库&#xff0c;如Ms Access、SQL Server等 (Windows XP 自带有Access和SQL Server的ODBC Driver)。我们就用QODBC对Access数据库进行访问。 Acces…

别再瞎搞了,耳朵都竖起来听我说,新手小白开发应该如何选择最合适你的JetBrains IDE版本类型和版本号! 今天一次性给你说清楚!

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…

windows环境下搭建redis集群

下面记录一下windows10环境下搭建redis3主3从集群&#xff0c;将过程分享出来&#xff0c;仅供学习研究使用。 1、redis集群 Redis集群关键点就是去掉中心化(与哨兵模式的区别)&#xff0c;当主机宕机&#xff0c;从节点回自动升级为主节点&#xff0c;具体请参考官网或相关大…

机器学习——KNN算法(手动代码,含泪)

徒手实现代码的过程&#xff0c;真是含泪和心酸&#xff0c;浪费了生命中的三天&#xff0c;以及工作中的划水一小时 终于滤清思路后&#xff0c;自己实现了KNN 都说KNN是最基础&#xff0c;最简单的分类器 放屁&#xff01;骗纸&#xff01;&#xff01;&#xff01;它的想法是…

第八章——向量代数与空间解析几何

目录 一、运算公式 二、平面的法线向量 注&#xff1a;加粗体为向量 一、运算公式 1.若a//b&#xff0c;那么aλb 若a⊥b&#xff0c;那么a*b0 2.若A(x1,y1,z1)&#xff0c;B(x2,y2,z2) 中点坐标&#xff1a;AB中点M(x1x2/2,y1y2/2,z1z2/2) 两点间的距离和模的计算&#x…

第3章 信息系统治理

文章目录 3.1.1 IT治理基础1. IT治理的驱动因素2. IT治理的目标价值3. IT治理的管理层次 3.1.2 IT治理体系1. IT治理关键决策2. IT治理体系框架3. IT治理核心内容4. IT治理机制经验&#xff08;建立IT治理机制的原则&#xff1a;简单、透明、适合&#xff09; 3.1.3 IT治理任务…

工作流引擎Flowable

这里写目录标题 1.Flowable基础1.1 入门学习 2.流程图设计器2.1 FlowableUI2.1.1 绘制流程图 1.Flowable基础 官方手册 1.1 入门学习 一、依赖 <dependencies><dependency><groupId>org.flowable</groupId><artifactId>flowable-engine</…