protobuf 详解

article/2025/8/30 8:15:38

protobuf简介

Protobuf是Protocol Buffers的简称,它是Google公司开发的一种数据描述语言,是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化 。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。

  1. protobuf是类似与json一样的数据描述语言(数据格式)

  2. protobuf非常适合于RPC数据交换格式

注意:protobuf本身并不是和gRPC绑定的。它也可以被用于非RPC场景,如存储等

protobuf的优劣势

1)优势:

  1. 序列化后体积相比Json和XML很小,适合网络传输

  2. 序列化反序列化速度很快,快于Json的处理速度

  3. 消息格式升级和兼容性还不错

  4. 支持跨平台多语言

2)劣势:

  1. 应用不够广(相比xml和json)

  2. 二进制格式导致可读性差

  3. 缺乏自描述

protoc安装(windows)

protoc就是protobuf的编译器,它把proto文件编译成不同的语言

下载安装protoc编译器(protoc)

下载protobuf:https://github.com/protocolbuffers/protobuf/releases/download/v3.20.1/protoc-3.20.1-win64.zip

解压后,将目录中的 bin 目录的路径添加到系统环境变量,然后打开cmd输入protoc查看输出信息,此时则安装成功

安装protocbuf的go插件(protoc-gen-go)

由于protobuf并没直接支持go语言需要我们手动安装相关插件

protocol buffer编译器需要一个插件来根据提供的proto文件生成 Go 代码,Go1.16+要使用下面的命令安装插件:

 go install google.golang.org/protobuf/cmd/protoc-gen-go@latest  // 目前最新版是v1.3.0

安装grpc(grpc)

 go get -u -v google.golang.org/grpc@latest    // 目前最新版是v1.53.0

安装grpc的go插件(protoc-gen-go-grpc)

说明:在google.golang.org/protobuf中,protoc-gen-go纯粹用来生成pb序列化相关的文件,不再承载gRPC代码生成功能,所以如果要生成grpc相关的代码需要安装grpc-go相关的插件:protoc-gen-go-grpc

 go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest  // 目前最新版是v1.3.0

protobuf语法

protobuf语法

  • 类型:类型不仅可以是标量类型(intstring等),也可以是复合类型(enum等),也可以是其他message

  • 字段名:字段名比较推荐的是使用下划线/分隔名称

  • 字段编号:一个message内每一个字段编号都必须唯一的,在编码后其实传递的是这个编号而不是字段名

  • 字段规则:消息字段可以是以下字段之一

    • singular:格式正确的消息可以有零个或一个字段(但不能超过一个)。使用 proto3 语法时,如果未为给定字段指定其他字段规则,则这是默认字段规则

    • optional:与 singular 相同,不过可以检查该值是否明确设置

    • repeated:在格式正确的消息中,此字段类型可以重复零次或多次。系统会保留重复值的顺序

    • map:这是一个成对的键值对字段

  • 保留字段:为了避免再次使用到已移除的字段可以设定保留字段。如果任何未来用户尝试使用这些字段标识符,编译器就会报错

简单语法

proto文件基本语法

 syntax = "proto3";              // 指定版本信息,不指定会报错package pb;                     // 后期生成go文件的包名// message为关键字,作用为定义一种消息类型message Person{string name = 1;   // 名字int32  age = 2 ;   // 年龄}​enum test{int32 age = 0;}

protobuf消息的定义(或者称为描述)通常都写在一个以 .proto 结尾的文件中:

  1. 第一行指定正在使用proto3语法:如果不这样做,协议缓冲区编译器将假定正在使用proto2(这也必须是文件的第一个非空的非注释行)

  2. 第二行package指明当前是pb包(生成go文件之后和Go的包名保持一致)

  3. message关键字定义一个Person消息体,类似于go语言中的结构体,是包含一系列类型数据的集合。

    • 许多标准的简单数据类型都可以作为字段类型,包括boolint32, floatdouble,和string

    • 也可以使用其他message类型作为字段类型。

在message中有一个字符串类型的value成员,该成员编码时用1代替名字。在json中是通过成员的名字来绑定对应的数据,但是Protobuf编码却是通过成员的唯一编号来绑定对应的数据,因此Protobuf编码后数据的体积会比较小,能够快速传输,缺点是不利于阅读。

message常见的数据类型与go中类型对比

.proto类型Go类型介绍
doublefloat6464位浮点数
floatfloat3232位浮点数
int32int32使用可变长度编码。编码负数效率低下——如果你的字段可能有负值,请改用sint32。
int64int64使用可变长度编码。编码负数效率低下——如果你的字段可能有负值,请改用sint64。
uint32uint32使用可变长度编码。
uint64uint64使用可变长度编码。
sint32int32使用可变长度编码。符号整型值。这些比常规int32s编码负数更有效。
sint64int64使用可变长度编码。符号整型值。这些比常规int64s编码负数更有效。
fixed32uint32总是四字节。如果值通常大于228,则比uint 32更有效
fixed64uint64总是八字节。如果值通常大于256,则比uint64更有效
sfixed32int32总是四字节。
sfixed64int64总是八字节。
boolbool布尔类型
stringstring字符串必须始终包含UTF - 8编码或7位ASCII文本
bytes[]byte可以包含任意字节序列

protobuff语法进阶

message嵌套

messsage除了能放简单数据类型外,还能存放另外的message类型:

 syntax = "proto3";          // 指定版本信息,不指定会报错package pb;                 // 后期生成go文件的包名// message为关键字,作用为定义一种消息类型message Person{string name = 1;  // 名字int32  age = 2 ;  // 年龄// 定义一个messagemessage PhoneNumber {string number = 1;int64 type = 2;}PhoneNumber phone = 3;}

message成员编号,可以不从1开始,但是不能重复,不能使用19000 - 19999

repeated关键字

repeadted关键字类似与go中的切片,编译之后对应的也是go的切片,用法如下:

 syntax = "proto3";              // 指定版本信息,不指定会报错package pb;                     // 后期生成go文件的包名// message为关键字,作用为定义一种消息类型message Person{string name = 1;   // 名字int32  age = 2 ;   // 年龄// 定义一个messagemessage PhoneNumber {string number = 1;int64 type = 2;}repeated PhoneNumber phone = 3;}

默认值

解析数据时,如果编码的消息不包含特定的单数元素,则解析对象对象中的相应字段将设置为该字段的默认值

不同类型的默认值不同,具体如下:

  • 对于字符串,默认值为空字符串

  • 对于字节,默认值为空字节

  • 对于bools,默认值为false

  • 对于数字类型,默认值为零

  • 对于枚举,默认值是第一个定义的枚举值,该值必须为0。

  • repeated字段默认值是空列表

  • message字段的默认值为空对象

enum关键字

在定义消息类型时,可能会希望其中一个字段有一个预定义的值列表

比如说,电话号码字段有个类型,这个类型可以是,home,work,mobile

我们可以通过enum在消息定义中添加每个可能值的常量来非常简单的执行此操作。示例如下:

 syntax = "proto3";              // 指定版本信息,不指定会报错package pb;                     // 后期生成go文件的包名// message为关键字,作用为定义一种消息类型message Person{string name = 1;   // 名字int32  age = 2 ;   // 年龄// 定义一个messagemessage PhoneNumber {string number = 1;PhoneType type = 2;}repeated PhoneNumber phone = 3;}​// enum为关键字,作用为定义一种枚举类型enum PhoneType {MOBILE = 0;HOME = 1;WORK = 2;}

如上,enum的第一个常量映射为0,每个枚举定义必须包含一个映射到零的常量作为其第一个元素。这是因为:

  • 必须有一个零值,以便我们可以使用0作为数字默认值。

  • 零值必须是第一个元素,以便与proto2语义兼容,其中第一个枚举值始终是默认值。

enum还可以为不同的枚举常量指定相同的值来定义别名。如果想要使用这个功能必须将allow_alias选项设置为true,负责编译器将报错。示例如下:

 syntax = "proto3";              // 指定版本信息,不指定会报错package pb;                     // 后期生成go文件的包名// message为关键字,作用为定义一种消息类型message Person{string name = 1;   // 名字int32  age = 2 ;   // 年龄// 定义一个messagemessage PhoneNumber {string number = 1;PhoneType type = 2;}repeated PhoneNumber phone = 3;}​// enum为关键字,作用为定义一种枚举类型enum PhoneType {// 如果不设置将报错option allow_alias = true;MOBILE = 0;HOME = 1;WORK = 2;Personal = 2;}

oneof关键字

如果有一个包含许多字段的消息,并且最多只能同时设置其中的一个字段,则可以使用oneof功能,示例如下:

 message Person{string name = 1; // 名字int32  age = 2 ; // 年龄//定义一个messagemessage PhoneNumber {string number = 1;PhoneType type = 2;}​repeated PhoneNumber phone = 3;oneof data{string school = 5;int32 score = 6;}}

定义RPC服务

如果需要将message与RPC一起使用,则可以在.proto文件中定义RPC服务接口,protobuf编译器将根据你选择的语言生成RPC接口代码。示例如下:

 //定义RPC服务service HelloService {rpc Hello (Person)returns (Person);}

注意:默认protobuf编译期间,不编译服务,如果要想让其编译,需要使用gRPC

protobuf编译

编译器调用

protobuf 编译是通过编译器 protoc 进行的,通过这个编译器,我们可以把 .proto 文件生成 go,Java,Python,C++, Ruby或者C# 代码

可以使用以下命令来通过 .proto 文件生成go代码(以及grpc代码)

 // 将当前目录中的所有 .proto文件进行编译生成go代码protoc --go_out=./ --go_opt=paths=source_relative *.proto

protobuf 编译器会把 .proto 文件编译成 .pd.go 文件

--go_out 参数

作用:指定go代码生成的基本路径

  1. protocol buffer编译器会将生成的Go代码输出到命令行参数go_out指定的位置

  2. go_out标志的参数是你希望编译器编写 Go 输出的目录

  3. 编译器会为每个.proto 文件输入创建一个源文件

  4. 输出文件的名称是通过将.proto 扩展名替换为.pb.go 而创建的

--go_opt 参数

protoc-gen-go提供了--go_opt参数来为其指定参数,可以设置多个:

  1. paths=import:生成的文件会按go_package路径来生成,当然是在--go_out目录

    • 例如,go_out/$go_package/pb_filename.pb.go

    • 如果未指定路径标志,这就是默认输出模式

  2. paths=source_relative:输出文件与输入文件放在相同的目录中

    • 例如,一个protos/buzz.proto输入文件会产生一个位于protos/buzz.pb.go的输出文件。

  3. module=$PREFIX:输出文件放在以 Go 包的导入路径命名的目录中,但是从输出文件名中删除了指定的目录前缀。

    • 例如,输入文件 pros/buzz.proto,其导入路径为 example.com/project/protos/fizz 并指定example.com/projectmodule前缀,结果会产生一个名为 pros/fizz/buzz.pb.go 的输出文件。

    • 在module路径之外生成任何 Go 包都会导致错误,此模式对于将生成的文件直接输出到 Go 模块非常有用。

--proto_path 参数

--proto_path=IMPORT_PATH

  • IMPORT_PATH是 .proto 文件所在的路径,如果忽略则默认当前目录。

  • 如果有多个目录则可以多次调用--proto_path,它们将会顺序的被访问并执行导入。

使用示例:

 protoc --proto_path=src --go_out=out --go_opt=paths=source_relative foo.proto bar/baz.proto// 编译器将从 `src` 目录中读取输入文件 `foo.proto` 和 `bar/baz.proto`,并将输出文件 `foo.pb.go` 和 `bar/baz.pb.go` 写入 `out` 目录。如果需要,编译器会自动创建嵌套的输出子目录,但不会创建输出目录本身

使用grpc的go插件

安装proto-gen-go-grpc

google.golang.org/protobuf中,protoc-gen-go纯粹用来生成pb序列化相关的文件,不再承载gRPC代码生成功能。生成gRPC相关代码需要安装grpc-go相关的插件protoc-gen-go-grpc

 // 安装protoc-gen-go-grpcgo install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest  // 目前最新版是v1.3.0

生成grpc的go代码:

 // 主要是--go_grpc_out参数会生成go代码protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative  *.proto

--go-grpc_out 参数

作用:指定grpc go代码生成的基本路径

命令会产生的go文件:

  1. protoc-gen-go:包含所有类型的序列化和反序列化的go代码

  2. protoc-gen-go-grpc:包含service中的用来给client调用的接口定义以及service中的用来给服务端实现的接口定义

--go-grpc_opt 参数

protoc-gen-go类似,protoc-gen-go-grpc提供 --go-grpc_opt 来指定参数,并可以设置多个

github.com/golang/protobuf 和 google.golang.org/protobuf

github.com/golang/protobuf

  1. github.com/golang/protobuf 现在已经废弃

  2. 它可以同时生成pb和gRPC相关代码的

用法:

 // 它在--go_out加了plugin关键字,paths参数有两个选项,分别是 import 和 source_relative--go_out=plugins=grpc,paths=import:.  *.proto

google.golang.org/protobuf

  1. github.com/golang/protobuf的升级版本,v1.4.0之后github.com/golang/protobuf仅是google.golang.org/protobuf的包装

  2. 它纯粹用来生成pb序列化相关的文件,不再承载gRPC代码生成功能,生成gRPC相关代码需要安装grpc-go相关的插件protoc-gen-go-grpc

用法:

 // 它额外添加了参数--go-grpc_out以调用protoc-gen-go-grpc插件生成grpc代码protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relativ

 


http://chatgpt.dhexx.cn/article/TubWK6JB.shtml

相关文章

protobuf介绍和语法

目录 前言 语法 标识符 字段 字段类型 proto2和proto3区别 前言 Protobuf即Protocol Buffers,是Google公司开发的一种跨语言和平台的序列化数据结构的方式,是一个灵活的、高效的用于序列化数据的协议。 与XML和JSON格式相比,pr…

Protobuf:一种更小、更快、更高效的协议

C/CLinux服务器开发/后台架构师知识体系 Protobuf介绍 Protobuf (Protocol Buffers) 是谷歌开发的一款无关平台,无关语言,可扩展,轻量级高效的序列化结构的数据格式,用于将自定义数据结构序列化成字节流,和将字节流反…

win10商店打不开_win10应用商店闪退是咋回事呢

win10虽然具有闪电般的开机速度,并且还新增了很多功能。但比较是全新的操作系统,所以难免会存在一些故障,这里小编就给大家讲讲win10应用商店闪退打不开怎么解决。 方法一 1,首先,打开开始菜单,进入设置&am…

电脑安装Linux闪退,win10系统运行内置Linux系统闪退如何处理

我们在win10系统电脑的使用中,有小伙伴在Linux系统的使用中出现了问题, win10系统运行内置Linux系统闪退的情况出现了,这是什么原因导致的呢,我们在win10系统运行内置Linux系统闪退如何处理,今天小编就来跟大家分享一下…

Java版mc闪退_本文传授win10运行mc闪退的具体操作对策

我们在使用电脑的时候遇到了win10运行mc闪退问题确实比较难受,要是你的电脑技术没有达到一定的水平,可能就不能解决这个win10运行mc闪退的情况。我们应当如何处理这个问题呢?小编先给大伙说说简单的措施:1、确保电脑中安装了 .NET…

(2022.5.27)【Win10】Windows10重置后微软商店闪退打不开、图片闪退打不开、UWP应用闪退打不开——可能的解决方案

更新日志 20220609 增加注意事项 注意事项 经过多为网友的反馈,目前这个方法是无法直接解决微软商店打不开的问题。因此,基于我目前的了解(6月9日),如果大家遇到这个问题,真的只能重新 U 盘安装系统了。…

win10内置计算机和天气闪退,win10系统中天气闪退怎么办?Win10天气应用闪退问题解决方法...

win10系统中天气闪退怎么办?最近有部分用户在安装了win10系统后发现自带的天气应用出现闪退的情况,点击天气应用,发现它启动了很久,然后就自动关闭了。之后再点击天气应用就闪退,打不开。而尝试打开别的应用却可以正常…

解决WIN10下应用商店不能用,闪退的情况

解决WIN10下应用商店不能用,闪退的情况 先说下我的情况,也是博主手贱,经常看PC上的某个文件或者程序不顺眼的话就会想办法把它干掉,为此重装过几次系统… 这一次是装了win10的周年更新后,烦人的cortana,onedrive等一些我不想要的APP又回来了,在暴力清理这些APP的时候,需要特殊…

win10java闪退怎么办_Win10应用打不开或闪退怎么办?解决方案在此

可能有一些用户升级Win10之后遇到了应用商店、应用打不开或闪退的问题,此时可尝试通过下面的一些方法来解决。 1、点击任务栏的搜索(Cortana小娜)图标,输入Powershell,在搜索结果中右键单击Powershell,选择“以管理员身份运行”。…

win10的c语言程序闪退,Win10专业版软件打不开闪退怎么办?

现在用到最多的Win10系统是Win10专业版,用户重装Win10专业版系统的目的就是为了解决电脑遇到的问题,然而重装系统后还是会出现许许多多的问题,比如说部分软件打不开了,闪退的问题。如果您也遇到了相同的问题,下面就是小…

win10安装虚拟机闪退_win10应用商店战争机器4闪退,无法运行。

创建日期 2018/01/07 win10应用商店战争机器4闪退,无法运行。 日志名称: System 来源: Microsoft-Windows-DistributedCOM 日期: 2018-01-07 14:05:10 事件 ID: 10001 任务类别: 无 级别: 错误 关键字:…

右击计算机管理打开会闪退,win10应用商店为什么会闪退 win10应用商店出故障怎么修复...

win10系统有个应用商店,在商店里用户可以下载一些软件应用,很多用户反馈win10应用商店老是闪退,重启也没有用,这该怎么办?下面小编为大家科普下win10应用商店闪退的解决方案,希望可以帮助到大家。 win10应用…

win10的c语言程序闪退,win10内置应用出现闪退怎么回事? win10打开应用总闪退的解决方法...

Windows10操作系统新增加很多实用的功能,对大家操作电脑有很大帮助。Win10专业版系统自带有相机功能、地图功能、时钟功能,同时还有一个应用商店功能,有的小伙伴说打开内置应用时出现闪退,究竟是哪里出现问题?针对此问…

win10的c语言程序闪退,win10 1909系统出现应用闪退如何解决

许多用户在升级更新到win10 1909版本系统之后,反映说遇到这样一个问题,就是使用应用的时候会出现闪退的现象,该怎么处理呢,下面给大家带来win10 1909系统出现应用闪退的解决措施。 一、重装应用 将闪退的应用卸载之后重新安装一下…

Window10 应用商店闪退问题

新装win10后打开应用商店,搜索软件直接闪退,查看了网上前人留下的经验发现还是没有解决问题,后来点开了电脑的设置 默认是选中第二项,点击第一项后,应用商店可以使用了 当然选中开发人员模式应用商店也是可以使用的

Win10应用商店、应用打不开或闪退的解决方法

越来越多小伙伴都将系统升级成Win10正式版了,win10功能强大令不少朋友感到非常满意,但也有一些朋友升级后却遇到了一些问题,比如应用商店、应用打不开或闪退的问题,今天快启动小编就跟大家介绍Win10应用商店、应用打不开或闪退的解决方法。 1、点击任务栏的搜索(Cortana小娜…

WIN10应用商店(MicrosoftStore)闪退解决方法!!!

本文参考了: CSDN博主「DreamOneDay」的文章https://blog.csdn.net/zyhj2010/article/details/52232749知乎作者千千之雪的文章https://www.zhihu.com/question/31001796/answer/1099015956 本方法适用于:更改过C:\ProgramFiles\WindowsApps权限的用户 如…

win10应用及应用商店闪退有效解决办法

近日遇到win10应用及应用商店闪退问题,在网上找寻各种方法,最终解决,记录下来,供以后查询。 方法 1/步骤1 1、在任务栏的搜索框中输入“Powershell”,然后在搜索结果中找到windows Powershell 鼠标右键单击并选择“以…

第6集丨JavaScript 使用原型(prototype)实现继承——最佳实战3

目录 一、原型继承与属性拷贝1.1 功能说明1.2 功能测试 二、多重继承2.1 功能实现2.2 功能测试 三、寄生式继承四、构造器借用4.1 简单实现4.2 进化版4.2.1 功能实现4.2.2 案例测试 五、借用构造器和原型复制六 综合案例6.1 需求说明6.2 代码实现 一、原型继承与属性拷贝 1.1 功…

Jstorm基础架构

整体架构 深度基于Zookeeper的调度系统。 Jstorm ZK路径 /-{storm.zookeeper.root} -- Jstorm在zookeeper上的根目录,需要在jstorm中配置~/.jstorm/storm.yaml| ||-/nimbus_master -- nimbus_master 的ip和端口| |-/nim…