【gRPC】ProtoBuf 语言快速学习指南

继上篇【gRPC】 在.Net core中使用gRPC了解了gRPC的使用,gRPC基于HTTP/2ProtoBufProtoBuf就非常有必要好好了解一下了,

那么ProtoBuf究竟是什么?

ProtoBuf =Google Protocol Buffer

是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。

是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。

可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。

ProtoBuf 是一种数据表达方式,google又说它是数据交换格式,交换 ,也就是说着眼点在数据的传输上。

在数据表达方式上,可以类比json或者xml,但是不同于 json 可以直接被读取解析,需要

  • 1.创建.proto文件,定义数据结构:维护一套对象协议

  • 2.protoc编译.proto文件生成读写接口

  • 3.调用接口实现序列化、反序列化以及读写

gRPC诞生于2015年,而ProtoBuf 最早从2001年开始就在谷歌内部使用了,后者强调的就是简单和性能,在谷歌内部广泛运用于存储和交换各种结构化信息,前者强调的是通信。

1. Message

systax="proto"message SearchRequest {string query = 1;int32 page_number = 2;int32 result_per_page = 3;
}
  • syntax:使用的语法,如果不指定,编译器就会按proto2编译。文件第一行必须是非空,非注释。

  • message:SearchRequest定义了3个字段

1.1 指定字段类型

你可以指定字段为标量类型,string,int32,当然也可以指定复合类型,包括枚举等其他一些类型。然后通过protocol buffer编译器去生成不同语言平台的代码。官方给出了相关的proto标量类型与不同语言平台类型映射表。

类型默认值

string>empty string

bytes>empty bytes

bool>false

数字类型>0

enums>定义的第一个枚举值0

枚举类型

message SearchRequest {string query = 1;int32 page_number = 2;int32 result_per_page = 3;enum Corpus {UNIVERSAL = 0;WEB = 1;IMAGES = 2;LOCAL = 3;NEWS = 4;PRODUCTS = 5;VIDEO = 6;}Corpus corpus = 4;
}

每个枚举类型必须包含一个常量,第一个常量必须是0,

message MyMessage1 {enum EnumAllowingAlias {option allow_alias = true;UNKNOWN = 0;STARTED = 1;RUNNING = 1;}
}

allow_alias设置为true,就可以将相同的值分配给不同的枚举常量。

字段为消息

message SearchResponse {repeated Result results = 1;
}message Result {string url = 1;string title = 2;repeated string snippets = 3;
}

ps:repeated可以用来存放N个相同类型的内容

导入定义

嵌套消息,在当前*.proto文件就如上使用。如果Result在其他.proto文件呢?

import "myproject/other_protos.proto";

字段为嵌套类型

message SearchResponse {message Result {string url = 1;string title = 2;repeated string snippets = 3;}repeated Result results = 1;
}

1.2 分配字段编号

每个字段都有一个独一无二的编号。这些编号作用就大了,因为消息是二进制格式,这些编号就是用来标识消息中的字段,这个可以类比一些通信协议中的编码格式。

  • 1-15需要1个字节编码

  • 16-2047需要两个字节

官方提示,频繁出现的消息元素定义至1-15,将来可能频繁出现的消息元素也要在1-15为其留点位置。

1.3 多个消息类型

message SearchRequest {string query = 1;int32 page_number = 2;int32 result_per_page = 3;
}message SearchResponse {...
}

1.4 注释

/* SearchRequest represents a search query, with pagination options to* indicate which results to include in the response. */message SearchRequest {string query = 1;int32 page_number = 2;  // Which page number do we want?int32 result_per_page = 3;  // Number of results to return per page.
}

1.5 保留字段

如果通过完全删除字段或注释来更新消息类型。如果以后加载相同.proto的旧版本,可能会导致严重问题,包括数据损坏、隐私漏洞等。

比如删除了编号1 的字段,修改为其他字段,服务端已更新,客户端还是旧版本,客户端和服务端的编号为1的字段不一致。

确保不会发生这种情况的一种方法是指定保留已删除字段的字段号。如果将来有任何用户试图使用这些字段标识符,协议缓冲区编译器将会提示。语法如下:

message Foo {reserved 2, 15, 9 to 11;reserved "foo", "bar";
}

1.6 Protocol buffer 编译器

编译器会根据选择的语言平台生成相应的代码

2.Services

消息类型定义完成后,便是我们使用gRPC的重头戏,Service=RPC(Remote Procedure Call).在proto文件中定义RPC service接口,编译器就会根据你选择的语言平台存根生成服务接口代码。看如下示例:

service SearchService {rpc Search (SearchRequest) returns (SearchResponse);
}
message SearchRequest {string query = 1;int32 page_number = 2;int32 result_per_page = 3;enum Corpus {UNIVERSAL = 0;WEB = 1;IMAGES = 2;LOCAL = 3;NEWS = 4;PRODUCTS = 5;VIDEO = 6;}Corpus corpus = 4;
}
message SearchResponse {message Result {string url = 1;string title = 2;repeated string snippets = 3;}repeated Result results = 1;
}
  • service-关键字

  • SearchService-服务名

  • Search-方法名

  • SearchRequest-传入的参数

  • SearchResponse-返回的参数

3.Packages

您可以向.proto文件添加一个包说明符,当然这个Packages是可选,主要是为了防止message 之间的命名冲突。

package foo.bar;
message Open { ... }

在C#中,除非在.proto文件中显式地指明选项csharp_namespace,否则包名就会在转换为PascalCase格式后,作为名称空间。更多其他语言参考官方文档说明。

4.Options

4.1 文件级别

顶级,不在任何消息,枚举或者服务的定义

option csharp_namespace = "GrpcService";package greet;

这个就是生成代码时命名空间(java就是包嘛),如果不指定csharp_namespace,如上描述,命名空间就会取package的名称:greet。

4.2 消息级别

仅在消息定义内部

4.3 字段级别

仅在字段定义内部

4.4 类型级别

枚举类型,枚举值,服务类型,服务方法,但是目前这个级别的还没啥用,可能未来为了涌现的新需求会开始发挥作用。

更多详情,示例用法,参考官方

5.编译

在.Net Core 3.0中,在上面的几个关键部分书写完成,基本上就能针对proto文件进行自动编译生成服务端或客户端代码,只需要进行各自的开发即可,这如丝般顺滑的体验,当然是微软为开发者行的方便,但是我们还是有必要了解一下刀耕火种的方式(仅仅是了解,有枪可以用,谁还去拼刺刀,刀快还是枪快?):

5.1 下载编译器

https://github.com/protocolbuffers/protobuf/releases/tag/v3.12.2

win64包

5.2 编译

protoc --proto_path=IMPORT_PATH --csharp_out=DST_DIR path/to/file.proto
  • --proto_path:proto文件的目录,可多次指定, -I可以简化命令

  • --cscharp_out:输出C#文件的位置,其他语言平台

    顾名思义,就不一一赘述

    • --cpp_out

    • --java_out

    • --python_out

    • --go_out

    • --ruby_out

    • --objc_out

    • --php_out

  • DST_DIR:可以指定为.zip,注意,如果输出存档已经存在,它将被覆盖;编译器不够智能,无法将文件添加到现有存档。

protoc -I=$SRC_DIR --csharp_out=$DST_DIR $SRC_DIR/*.proto

生成实体类,接口

protoc.exe -I="." .\greet.proto --csharp_out="./code"

生成grpc服务

protoc.exe -I="." .\greet.proto --csharp_out="./code"   --grpc_out="./code"  --plugin=protoc-gen-grpc=grpc_csharp_plugin.exe
--grpc_out: protoc-gen-grpc: 系统找不到指定的文件。
  • --grpc_out:csharp_out是输出类似于咱们平时写的实体类,接口,定义之类的。生成的文件叫,额,就叫*.cs吧.grpc_out是跟服务相关,创建,调用,绑定,实现相关。生成的玩意叫xxxGrpc.cs。

  • --plugin=protoc-gen-grpc=grpc_csharp_plugin.exe 这个就是csharp的插件。插件nuget帮我们下下来了,目录%UserProfile%\.nuget\packages\grpc.tools\2.29.0\tools\windows_x64\grpc_csharp_plugin.exe

这里通过命令刀耕火种生成xxxGrpc.cs失败了,目前没找到解决方案,相关Stack Overflow问题,但是并没有解决。或许微软官方知道原因,毕竟微软进行了工具集成,生成无误。有知道原因或者解决方案的,请在下方评论指出。灰常感谢~

6.序列化与反序列化

序列化

using Google.Protobuf;
Person john = new Person
{Id = 1234,Name = "John Doe",Email = "jdoe@example.com",Phones = { new Person.Types.PhoneNumber { Number = "555-4321", Type = Person.Types.PhoneType.Home } }
};
using (var output = File.Create("john.dat"))
{john.WriteTo(output);
}

反序列化

using gen_namespaceusing (var input = File.OpenRead("john.dat"))
{Person john;john = Person.Parser.ParseFrom(input);
}

参考链接

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

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

https://www.cnblogs.com/nmslanx/articles/8242105.html

https://www.jianshu.com/p/a24c88c0526a

https://www.cnblogs.com/makor/p/protobuf-and-grpc.html

https://en.wikipedia.org/wiki/Protocol_Buffers

https://developers.google.com/protocol-buffers/docs/csharptutorial#parsing-and-serialization

长按二维码关注

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

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

相关文章

vspythonqt混合_PYQT5 vscode联合操作qtdesigner的方法

除了使用pycharm外,还可使用vscode来操作pyqt,方法如下:1. 在vscode中配置相关的pyqt的相关根据自己实际情况修改第一项pyqt的路径2. 创建一个文件夹,右键,最后一项可以创建一个新窗口创建的新窗口后缀为 .ui右键中有以…

TIOBE 1 月榜单:Python年度语言四连冠,C 语言再次第一

喜欢就关注我们吧!TIOBE 公布了 2021 年 1 月的编程语言排行榜。TIOBE 本月公布了 2020 年度编程语言,Python 获得四连冠,是过去一年中最受欢迎的编程语言。Python 在 2020 年实现了 2.01% 的正增长;C 紧随其后&#x…

A piecture of J2EE Core Patterns

这张图是J2EE Core Patterns里面的一幅图片,在Enterprise Solution Patterns Using Microsoft.Net里面虽然模式的概念与应用大同小异,但是那张表现架构模式整体的图感觉有点不直观,相比之下这幅图显得更清晰一点。 发到这里供大家参考学习:&#xff09…

孙丕恕离开浪潮 仪器厂历时60年成为服务器龙头企业

2020年12月31日浪潮集团有限公司董事会选举邹庆忠为公司董事长(法定代表人);孙丕恕不再担任公司董事长;公司不再聘任孙丕恕为首席执行官。另外,经省委研究决定,拟任省直部门(单位)副…

java 数组 树_java使用顺序数组实现二叉树

顺序数组实现二叉树实现原理对于下标为index的节点其满足1.左孩子节点的下标为2index12.右孩子节点的下标为2index2代码实现package tree;public class ArrayBinaryTree {private int[] arr;public ArrayBinaryTree(int[] arr){this.arrarr;}public void preOrder(int index){i…

【Docker】Asp.net core在docker容器中的端口问题

还记得【One by one系列】一步步学习docker(三)——实战部署dotnetcore中遇到的问题么?容器内部启动始终是80端口,并不由命令左右。docker run --name container-name -p 81:5000 mywebapi所谓知其然就要知其所以然,浅…

.net 5.0 中的 JsonConsole

asp.net core 5.0 中的 JsonConsoleIntroasp.net core 5.0 中日志新增了 JsonConsole,还是输出日志到 Console,但是会应用 Json 格式的一个 Formatter 把日志格式化成 json 再输出到控制台Sample一起来看一个示例,以我的一个小项目为例子来演…

采用开源软件搭建WebGIS系统(6)数据格式

[本文版权由xiaotievip.sina.com所有,转载需得到作者同意。] 在国家基础地理信息中心下载到的数据格式是Shape file数据。Shape file数据由3个文件构成,*.shp,*.dbf和*.shx,分别存储空间数据、属性数据和两者间的关系。*.shp得专门…

.NET Core 使用Topshelf方式创建Windows服务

Topshelf是一个.NET Standard库,它消除了在.NET Framework和.NET Core中创建Windows服务的那些麻烦。安装Install-Package Topshelf代码using System; using System.Collections.Generic; using System.Text; using Topshelf;namespace ConsoleApp2222 {public clas…

Roslyn 使用 Directory.Build.props 管理多个项目配置

在一些大项目需要很多独立的仓库来做,每个仓库之间都会有很多相同的配置,本文告诉大家如何通过 Directory.Build.props 管理多个项目配置在我的 MVVM 框架需要三个不同的库,一个是 Framework 另外两个是 WPF 和 UWP 这三个库有很多重复的配置…

java 中符号_谁能告诉我java中符号的用法,见代码

展开全部大家都知道Vector以及其他的容器可以不加任何修饰地e68a8462616964757a686964616f31333236373765存储任何类型的对象,这给我们带来了极大的方便,也使得容器很容易被复用,但是大多数时候我们可能需要只能存储某一类型对象的Vector,这是…

在.NET Core中使用Channel(一)

我最近一直在熟悉.net Core中引入的新Channel<T>类型。我想在它第一次发布的时候我了解过它&#xff0c;但是有关文章非常非常少&#xff0c;我不能理解它们与其他队列有什么不同。在使用了一段时间后&#xff0c;我终于看到了它们的吸引力和真正的力量。最值得注意的是大…

java控制系统音量_Java 控制 Windows 系统音量-Go语言中文社区

目录1、使用 Java 来控制 Windows 系统音量&#xff0c;使用 JNA 调用 windows 底层 API 因为有点麻烦&#xff0c;所以这里采用纯 Java API结合 VBS 脚本的方式进行控制。2、可以参考《VBS 控制 Windos 系统音量 及视频播放》&#xff0c;本文同样是利用 VBS 来控制&#xff0…

【Hook】postman工具的代码生成工具让它锦上添花

修改postman工具的代码生成工具加入response自动生成POJO代码如上图可以快速把请求这个动作转成code&#xff0c;减少重复性劳动。但是有一点我觉得可以优化下 就是返回的json如果也能自动转成代码就好了。不然在需要把json序列化成java或者csharp的POJO对象时还得自己coding转…

使用BeetleX.ESDoc构建文档搜索功能

BeetleX.ESDoc组件是基于ElasticSearch服务的文档搜索扩展组件。它在BeetleX.Elasticsearch的基础上包装一些基于文档检索的功能和方法&#xff0c;可以让你在不了解ElasticSearch API的情况下直接存储&#xff0c;删除和搜索相关信息。信息结构BeetleX.ESDoc定义了一个基础的文…

日产汽车源码遭泄露

喜欢就关注我们吧&#xff01;日产北美公司开发和使用的移动应用及内部工具的源代码于近日在网上泄露&#xff0c;原因是该公司错误配置了其中一台 Git 服务器。瑞士软件工程师 Tillie Kottmann 向 ZDNet 透露&#xff0c;此次泄露源于一台配置错误的 Bitbucket Git 服务器的信…

中台的故事结束了?

大家好&#xff0c;我是Z哥。所谓30年河东30年河西&#xff0c;最近阿里开始去中台了。这是不是意味着中台时代的落幕&#xff0c;去中心化时代的开始&#xff1f;谁都说不准。但是我们可以来思考一下这个事情背后释放出了什么样的信号。对我们普通人&#xff0c;特别是互联网行…

java树算法_Java数据结构算法(三)树

本文旨作于收集整理使用&#xff01;&#xff01;导航一、树树(Tree)是n(n≥0)个结点的有限集&#xff0c;n0称之为空树。在非空树种&#xff1a;当有且仅有一个特定的称为根(Root)的结点&#xff1b; 其余结点可以划分为m(m&#xff1e;0)个互不相交的有限集T1、T2 、…、Tm&a…

Blazor VS 传统Web应用程序

原文作者: Christian Findlay原文链接&#xff1a;https://christianfindlay.com/2020/07/09/blazor-vs-traditional-web-apps/Blazor是Microsoft团队开发的单页面应用程序&#xff08;SPA&#xff09;框架&#xff0c;它是与React&#xff0c;Angular和Vue.js有相同之处&#…

如何在 Web Forms 中引入依赖注入机制

依赖注入技术就是将一个对象注入到一个需要它的对象中&#xff0c;同时它也是控制反转的一种实现&#xff0c;显而易见&#xff0c;这样可以实现对象之间的解耦并且更方便测试和维护&#xff0c;依赖注入的原则早已经指出了&#xff0c;应用程序的高层模块不依赖于低层模块&…