如果你要给 .Net Core 寻找一个通信框架,或 寻找一个多平台多语言的通信框架,gRPC 是不错的选择。
gRPC 支持 C++、C#、Dart、Go、Java、Node、php、python、ruby、objective-C、WebJS,跨平台,跨语言。
gRPC (g = google, RPC = Remote Procedure Call [远程过程调用])
本教程简介
本教程使用 .Net Core 和 Visual Studio 开发工具
本教程目的:
- 学习 Protocol Buffers
- 学习 gRPC
- 使用 gRPC 实现一个简单的聊天室
为什么学习 gRPC 之前要先学习 Protocol Buffers,因为:
- gRPC 的数据序列的方式是使用 Protocol Buffers。
- gRPC 描述通信协议的方式也是使用 .proto文件。
Protocol Buffers 简介
Protocol Buffers 是 google 的一个开源项目,它是一种灵活、高效、自动化,用于序列化结构化数据,如 XML(json),但更小(smaller),更快(faster),更简单(simpler)。
和 XML(json) 比,Protocol Buffers
- 更小:比 XML 小 3 到 10 倍
- 更快:比 XML 快 20 到 100 倍
- 更简单:序列化过程比 XML 简单(底层简单,编码复杂了)
优点的原因在于:
Protocol Buffers 序列化采用 Varint 编码
Varint 一种紧凑的表示数字的方法。它用一个或多个字节来表示一个数字,值越小的数字使用越少的字节数。
这能减少用来表示数字的字节数。封解包的速度
XML 封解包过程需要从文件中读取出字符串,再转换为 XML 文档对象结构模型。之后,再从 XML 文档对象结构模型中读取指定节点的字符串,最后再将这个字符串转换成指定类型的变量。这个过程非常复杂,其中将 XML 文件转换为文档对象结构模型的过程通常需要完成词法文法分析等大量消耗 CPU 的复杂计算。
反观 Protocol Buffers,它只需要简单地将一个二进制序列,按照指定的格式读取到 编程语言 对应的结构类型中就可以了。
因此对应的缺点是:Protocol Buffers 序列化成二进制后,可读性差。
所以:
如果是做 前后端分离的通信数据序列,还是选择json吧,
如果是做 服务与服务之间的通信数据序列,可以考虑选择 Protocol Buffers。
定义序列化格式
回想一下为了将数据序列化成 XML(json),我们一般会先根据来编写对应的类(数据结构),
但各种语言定义数据结构的语法是不一样的,而使用 Protocol Buffers 是将想序列化的数据结构定义在一个 .proto文件中,
然后使用 Protocol Buffers 编译器 将其生成各语言对应的类(数据结构),还包含了序列化和反序列化方法。
接下来我们来看看官方教材中 addressbook.proto 学习一下是如何在 .proto文件中定义数据结构
1 |
|
每一个元素都有 = 1
, = 2
这样的标记,这些标记是字段在二进制编码内的唯一标识标签,
标签数字 1-15 比更大的数字需要更少的字节编码,做为优化你可以为常用的或 repeated
元素使用这些标签数字,
把 16 以上的标签留给不经常使用的元素。
重复字段的每一个元素都需要重新编码标签数字,所以重复字段特别适合这种优化。
更多语法规则,请浏览 官方文档 (可能需要梯子),或者搜索:Protobuf 语言指南
编译 Protocol Buffers
现在我们已经有了一个 .proto文件,接下来我们需要做的是生成相关的类,
这些类用来序列化和反序列化 AddressBook 消息(包含 Person和 PhoneNumber)。
为了能完成这样的工作,你需要运行 Protocol Buffers 的编译器,编译你的 .proto文件。
Protocol Buffers 编译器安装
选择 protoc-x.x.x-win32.zip
x.x.x表示版本,
另外该下载页面,还包含了不同的语言的 gRPC 实现和 Demo,有兴趣的可以下载之。
解压zip文件,可以看到 bin
文件夹中有一个 protoc.exe
文件,
现在将 bin
文件夹改名成 protoc
文件夹,将 protoc
文件夹复制到C盘。
接下来,我们需要添加 环境变量
- 右击
我的电脑
(win10是此电脑
) 属性
高级系统设置
环境变量
- 双击
path
- 点击
浏览
然后选择C盘下的protoc
文件夹 确定
打开 cmd
,输入 protoc --version
如有输出版本,则说明安装成功。
接下来,看看怎么把 addressbook.proto 编译生成我们需要的 C# 代码。
1 | protoc --csharp_out=$DST_DIR $SRC_DIR/addressbook.proto |
--csharp_out
: 是指,将其生成 C# 代码文件。$DST_DIR
:是指生成到哪个目标文件夹,需要替换成具体路径。$SRC_DIR
:源文件夹,需要替换成具体路径。
执行命令前,先将 google.protobuf.Timestamp last_updated = 5;
注释掉,因为我们没有import对应的包。
执行命令后,应该会在目标文件夹中生成一个 Addressbook.cs
文件。
那么问题就来了,如果 .proto 文件多,而且每次修改都要输入命令生成,是多么蛋疼的事情,
好在我们有宇宙最强大的 IDE Visual Studio,而且 Google 也为 VS 写了相关的工具。
结合 Visual Studio 自动化编译
因为我们的目标是使用 gRPC 实现一个简单的聊天室,所以先创建整个解决方案吧。
1 | Chat.sln |
首先在 Chat.Protocol.csproj
项目下,创建一个 addressbook.proto
文件,该文件的内容依然和上面的一样。
但该文件没有语法高亮,也没有智能提示,
所以点击 VS 菜单中的 工具
→ 扩展与更新
→ 联机
→ 搜索 Protobuf
安装 Protobuf Language Service
,
重启 VS 后,proto文件就有语法高亮和智能提示了。
(该插件最后更新是2017年,VS Code上也有相关的插件,比较新,提示得比较好)
Protobuf Language Service
只是语法高亮和智能提示,并不会将 proto 文件内容生成相应的代码。
右击 解决方案'Chat'
→ 管理解决方案的 NuGet 程序包(N)...
给 Chat.Protocol
项目,添加
Google.Protobuf
这个提供序列化和反序列化的一些扩展方法。Grpc.Tools
这个提供将 proto 文件生成相应代码,并不是添加了就行,还需要相关设置。Grpc
这个是 Grpc 的实现。
让 Chat.Server
引用 Chat.Protocol
,
然后在 Chat.Server
中的 Program.cs
中敲 Tutorial
并没有相关的提示,
即使你右击 Chat.Protocol
→ 生成(U)
也不会有。
现在我们需要右击 addressbook.proto
→ 属性(R)
→ 生成操作
选择 Protobuf compiler
这个时候再右击 Chat.Protocol
→ 生成(U)
,那么在 Chat.Server
中则有相应的 Tutorial
命名空间和 AddressBook
类了。
那么生成的代码到底在哪里呢?请查看 Chat.Protocol
下 obj
文件夹下的文件,你会有所发现…
序列化数据
1 | using System; |
结束语
本章讲解了 Protocol Buffers 是什么,以及各种相关工具的应用,
下一章将讲解 gRPC 的 Hello World 例子,开始进入 gRPC 的大门。