grpc系列- protobuf详解
Protocol Buffers 是一种与语言、平台无关,可扩展的序列化结构化数据的方法,常用于通信协议,数据存储等等。相较于 JSON、XML,它更小、更快、更简单,因此也更受开发人员的青眯。
基本语法
syntax = “proto3”;
package model;
service MyServ {
rpc Query(Request) returns(Reply);
}
message Student {
int64 id = 1;
string name = 2;
int32 age = 3;
}
定义完 proto文件后,生成相应语言的代码
protoc --proto_path=. --go_out=plugins=grpc,paths=source_relative:. xxxx.proto
--proto_path
或者 -I
参数用以指定所编译源码(包括直接编译的和被导入的 proto 文件)的搜索路径
--go_out
参数之间用逗号隔开,最后用冒号来指定代码目录架构的生成位置 ,--go_out=plugins=grpc
参数来生成gRPC相关代码,如果不加plugins=grpc
,就只生成message
数据
eg:--go_out=plugins=grpc,paths=import:. 。注意一下 paths 参数,他有两个选项,import 和 source_relative 。默认为 import ,代表按照生成的 go 代码的包的全路径去创建目录层级,source_relative 代表按照 proto 源文件的目录层级去创建 go 代码的目录层级,如果目录已存在则不用创建
protoc
是通过插件机制实现对不同语言的支持。比如 --xxx_out
参数,那么protoc将首先查询是否有内置的xxx插件,如果没有内置的xxx插件那么将继续查询当前系统中是否存在protoc-gen-xxx命名的可执行程序。
例如,生成 c++代码
protoc -I . --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` --cpp_out=. *.proto
导入依赖的proto
文件
为了方便,会把公共的一些字段放到一个proto
文件里,如果有需要,就把这个proto
文件impot
进去,比如,我现在的组织结构好下
common.proto
文件里只有个简单的message
syntax = "proto3";
package protos;
option go_package = "protos";
option java_package = "com.proto";
message Result {
string code = 1;
string desc = 2;
bytes data = 3;
}
目录api
里student_api.proto
在这个文件里,我们导入了common.proto
,还有其他需要的文件
syntax = "proto3";
package api;
option go_package = "protos/api";
option java_package = "com.proto.api";
import "protos/common.proto";
import "protos/model/students.proto";
import "google/protobuf/empty.proto";
service StudentSrv {
rpc NewStudent(model.Student) returns (protos.Result);
rpc StudentByID(QueryStudent) returns (QueryStudentResponse);
rpc AllStudent(google.protobuf.Empty) returns(stream QueryStudentResponse);
rpc StudentInfo(stream QueryStudent) returns(stream QueryStudentResponse);
}
message QueryStudent {
int64 id = 1;
}
message QueryStudentResponse {
repeated model.Student studentList = 1;
}
在执行protoc
的时候,我们要指定这些需文件的查找路径,在项目的根目录里执行protoc
进行代码生成
protoc -I=. --go_out=plugins=grpc:. --go_opt=paths=source_relative protos/api/*.proto
上面的-I
指定了当前目录,就是说可以从当前目录开始找proto
文件
protoc 生成了什么
以 student.proto
为例
syntax = "proto3";
package model;
option go_package = "protos/model";
option java_package = "com.proto.model";
message Student {
int64 id = 1;
string name = 2;
int32 age = 3;
}
message StudentList {
string class = 1;
repeated Student students = 2;
string teacher = 3;
repeated int64 score = 4;
}
执行完protoc
后,大概看一下生成的的go
文件
type Student struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
Age int32 `protobuf:"varint,3,opt,name=age,proto3" json:"age,omitempty"`
}
state
保存 proto文件的反射信息 sizeCache
序列化的数据总长度 unknownFields
不能解析的字段
剩下的字段是我们message
里定义的信息,主要看一下tag
信息
protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"
,说明这个字段是protobuf的varint
类型,index
为1
name为id
,使用proto3
协议
还有一个byte
数组的file_protos_model_students_proto_rawDesc
一眼看上去就有点蒙,这一坨是什么?开源的好处就是,我可以很清楚的看清他是做什么的,
这个file_protos_model_students_proto_rawDesc
是proto
里数据的描述信息。如 proto
的路径、包名称,message
信息等等。
file_protos_model_students_proto_rawDesc
描述信息有什么用呢?
当我们在执行proto.Marshal
的时候,会对传入的参数Message
进行验证,比如每个message
字段的index
、数据类型,是否和file_protos_model_students_proto_rawDesc
一致。如果不一致就说明是有问题的。
protobuf支持的数据类型
protobuf
目前支持这5种数据类型,还有2个是已经废弃了。protobuf
是语言无关的,也就是说,无论具体的语言支持哪些数据类型,在marshal
的时候都要转换成这几种,在unmarshal
的时候再转换成具体语言的类型
我们把一个结构转换成json
Student {
Id: 1,
Name: "孙悟空",
Age: 300,
}
{
"id": 1,
"name": "孙悟空",
"age": 300
}
转换成 protobuf
数据格式
1000 1 10010 1001 11100101 10101101 10011001 11100110 10000010 10011111 11100111 10101001 10111010 11000 10101100 10
转换成十进制
8 1 8 9 229 173 153 230 130 159 231 169 186 24 172 2
json
一眼就能看懂是什么 ,protobuf
数据格式看不明白,下面来解释这些数据都是什么。
index 和类型
先说一下第一个byte 1000
这个表示的是字段的index
和类型,
protobuf
把一个字段的 index 和类型放在了一起
(field_number << 3) | wire_type
最后3个bit为类型,前面的bit为index
0000 1000
首位为标识位,index为 1 后三位为wire_type:0(Varint类型)再比如 10010
index: 2 wire_type: 2(Length-delimited类型)
Varint类型
Varint
数据类型,最高位(msb)标志位,为1说明后面还有byte,0说明后面没有byte,使用后面的7个Bit位存储数值
Id: 1
protobuf对应的数据是0000 0001
这个很好理解
Age: 300
protobuf对应的数据是1010 1100 0000 0010
,这个是怎么计算的呢?
protobuf数据 1010 1100 0000 0010
去掉最高位 010 1100 000 0010
连接剩余 0100101100
计算 256 + 32 + 8 + 4 = 300
Length-delimited 类型
字符串内存的表现形式protobuf
一个汉字占3个byte
“孙悟空”内存的数据
11100101 10101101 10011001 11100110 10000010 10011111 11100111 10101001 10111010
“孙悟空”前面的一个byte:1001
这个数值有什么意义?对,字符串长度 9
Length-delimited
类型的数据第一个byte是数据的长度,后面是具体的数据信息,数据大同小异
grpc系列- protobuf详解的更多相关文章
- 通讯协议序列化解读(一) Protobuf详解教程
前言:说到JSON可能大家很熟悉,是目前应用最广泛的一种序列化格式,它使用起来简单方便,而且拥有超高的可读性.但是在越来越多的应用场景里,JSON冗长的缺点导致它并不是一种最优的选择. 一.常用序列化 ...
- PHP输出缓存ob系列函数详解
PHP输出缓存ob系列函数详解 ob,输出缓冲区,是output buffering的简称,而不是output cache.ob用对了,是能对速度有一定的帮助,但是盲目的加上ob函数,只会增加CPU额 ...
- 反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) C#中缓存的使用 C#操作redis WPF 控件库——可拖动选项卡的TabControl 【Bootstrap系列】详解Bootstrap-table AutoFac event 和delegate的分别 常见的异步方式async 和 await C# Task用法 c#源码的执行过程
反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) 背景介绍: 为了平衡社区成员的贡献和索取,一起帮引入了帮帮币.当用户积分(帮帮点)达到一定数额之后,就会“掉落”一定数量的“帮帮 ...
- SignalR新手系列教程详解总结(转)
SignalR新手系列教程详解总结 GlobalHost.ConnectionManager.GetHubContext<TodoListHub>() .Clients.Clients(l ...
- 猫哥网络编程系列:详解 BAT 面试题
从产品上线前的接口开发和调试,到上线后的 bug 定位.性能优化,网络编程知识贯穿着一个互联网产品的整个生命周期.不论你是前后端的开发岗位,还是 SQA.运维等其他技术岗位,掌握网络编程知识均是岗位的 ...
- 【WebApi系列】详解WebApi如何传递参数
WebApi系列文章 [01]浅谈HTTP在WebApi开发中的运用 [02]聊聊WebApi体系结构 [03]详解WebApi参数的传递 [04]详解WebApi测试和PostMan [05]浅谈W ...
- css3系列之详解perspective
perspective 简单来说,就是设置这个属性后,那么,就可以模拟出像我们人看电脑上的显示的元素一样.比如说, perspective:800px 意思就是,我在离屏幕800px 的地方观看这 ...
- 【tomcat系列】详解tomcat架构(上篇)
java中,常用的web服务器一般由tomcat,weblogic,jetty,undertwo等,但从用户使用广泛度来说,tomcat用户量相对比较大一些,当然这也基于它开源和免费的特点. 从软件架 ...
- Java并发包源码学习系列:详解Condition条件队列、signal和await
目录 Condition接口 AQS条件变量的支持之ConditionObject内部类 回顾AQS中的Node void await() 添加到条件队列 Node addConditionWaite ...
随机推荐
- 怎么用Iometer测试存储性能
1.Disk Targets选项栏中选择要测试的磁盘,1 per target of Outstanding I/Os 保持默认即可. 2.在Access Specifications栏中新建测试条件 ...
- Beta冲刺随笔——Day_Six
这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 Beta 冲刺 这个作业的目标 团队进行Beta冲刺 作业正文 正文 其他参考文献 无 今日事今日毕 林涛: ...
- Mac下打开DDMS(AndroidDeviceMonitor)白屏
mac打开AndroidStudio下的ddms(也就是AndroidDeviceMontor)白屏,是由于jdk版本号较高不兼容导致的,因此需要将jdk降为jdk1.8.0_144就可以来了,但是要 ...
- 痞子衡嵌入式:深入i.MXRT1050系列ROM中串行NOR Flash启动初始化流程
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是深入i.MXRT1050系列ROM中串行NOR Flash启动初始化流程. 从外部串行NOR Flash启动问题是i.MXRT系列开发最 ...
- [从源码学设计]蚂蚁金服SOFARegistry之消息总线异步处理
[从源码学设计]蚂蚁金服SOFARegistry之消息总线异步处理 目录 [从源码学设计]蚂蚁金服SOFARegistry之消息总线异步处理 0x00 摘要 0x01 为何分离 0x02 业务领域 2 ...
- 老猿学5G:融合计费场景的离线计费会话的Nchf_OfflineOnlyCharging_Update 更新操作过程
☞ ░ 前往老猿Python博文目录 ░ 一.Nchf_OfflineOnlyCharging_Update消息交互过程 Nchf_OfflineOnlyCharging_Update消息是是5G融合 ...
- PyQt(Python+Qt)学习随笔:model/view架构中的两个标准模型QStandardItemModel和QFileSystemModel
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.PyQt中的标准模型 PyQt和Qt提供了两个标准模型QStandardItemModel和QF ...
- PyQt(Python+Qt)学习随笔:QColumnView的resizeGripsVisible属性
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QColumnView在一个视图中展示多个列表,每个下级列表是上一个列表的数据项的分支, QColu ...
- 第七篇 Scrum 冲刺博客
一.站立式会议 1. 会议照片 2. 工作汇报 团队成员名称 昨日完成的工作 今天计划完成的工作 工作中遇到的困难 陈锐基 - 封装消息组件- 我的关注和我的粉丝页面布局- 强化表白墙组件并和详情页对 ...
- Spring RestTemplate具备负载均衡功能
在创建RestTemplate的Bean时使用@LoadBalanced注解, 就可以自动配置为使用ribbon.如下面的示例所示: @Configuration public class MyCo ...