Protobuf 的 proto3 与 proto2 的区别

转自:https://solicomo.com/network-dev/protobuf-proto3-vs-proto2.html

这是一篇学习笔记。在粗略的看了 Protobuf 的文档中关于 proto2 和 proto3 的说明后,记录下了几点 proto3 区别于 proto2 的地方。

总的来说,proto3 比 proto2 支持更多语言但 更简洁。去掉了一些复杂的语法和特性,更强调约定而弱化语法。如果是首次使用 Protobuf ,建议使用 proto3 。

  1. 在第一行非空白非注释行,必须写:

    syntax = "proto3";

  2. 字段规则移除了 “required”,并把 “optional” 改名为 “singular”1

    在 proto2 中 required 也是不推荐使用的。proto3 直接从语法层面上移除了 required 规则。其实可以做的更彻底,把所有字段规则描述都撤销,原来的 repeated 改为在类型或字段名后加一对中括号。这样是不是更简洁?

  3. “repeated”字段默认采用 packed 编码;

    在 proto2 中,需要明确使用 [packed=true] 来为字段指定比较紧凑的 packed 编码方式。

  4. 语言增加 Go、Ruby、JavaNano 支持;

  5. 移除了 default 选项;

    在 proto2 中,可以使用 default 选项为某一字段指定默认值。在 proto3 中,字段的默认值只能根据字段类型由系统决定。也就是说,默认值全部是约定好的,而不再提供指定默认值的语法。

    在字段被设置为默认值的时候,该字段不会被序列化。这样可以节省空间,提高效率。

    但这样就无法区分某字段是根本没赋值,还是赋值了默认值。这在 proto3 中问题不大,但在 proto2 中会有问题。

    比如,在更新协议的时候使用 default 选项为某个字段指定了一个与原来不同的默认值,旧代码获取到的该字段的值会与新代码不一样。

    另一个重约定而弱语法的例子是 Go 语言里的公共/私有对象。Go 语言约定,首字母大写的为公共对象,否则为私有对象。所以在 Go 语言中是没有 public、private 这样的语法的。

  6. 枚举类型的第一个字段必须为 0 ;

    这也是一个约定。

  7. 移除了对分组的支持;

    分组的功能完全可以用消息嵌套的方式来实现,并且更清晰。在 proto2 中已经把分组语法标注为『过期』了。这次也算清理垃圾了。

  8. 旧代码在解析新增字段时,会把不认识的字段丢弃,再序列化后新增的字段就没了;

    在 proto2 中,旧代码虽然会忽视不认识的新增字段,但并不会将其丢弃,再序列化的时候那些字段会被原样保留。

    我觉得还是 proto2 的处理方式更好一些。能尽量保持兼容性和扩展能力,或许实现起来也更简单。proto3 现在的处理方式,没有带来明显的好处,但丢掉了部分兼容性和灵活性。

    [2017-06-15 更新]:经过漫长的讨论,官方终于同意在 proto3 中恢复 proto2 的处理方式了。 可以通过这个文档了解前因后果及时间线。

  9. 移除了对扩展的支持,新增了 Any 类型;

    Any 类型是用来替代 proto2 中的扩展的。目前还在开发中。

    proto2 中的扩展特性很像 Swift 语言中的扩展。理解起来有点困难,使用起来更是会带来不少混乱。

    相比之下,proto3 中新增的 Any 类型有点像 C/C++ 中的 void* ,好理解,使用起来逻辑也更清晰。

  10. 增加了 JSON 映射特性;

    语言的活力来自于与时俱进。当前,JSON 的流行有其充分的理由。很多『现代化』的语言都内置了对 JSON 的支持,比如 Go、PHP 等。而 C++ 这种看似保罗万象的学院派语言,因循守旧、故步自封,以致于现出了式微的苗头。

  11. 实际上,这样说并不准确,但这样理解起来更简单。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------

转自:http://ju.outofmemory.cn/entry/235526

本文编写时, Google 官方的 protobuf 版本是3.0.0beta

下面介绍下proto3的一些细节变化


Proto3的语法变化

语法标记

这个版本的protoc的protobuf编译器已经可以支持proto2语法和proto3的语法

如果你的proto文件没有添加syntax说明的话, 用这个版本的编译器会报错, 提示你默认proto2支持, 请添加语法标记

syntax = "proto2";

optional不需要了

只保留repeated标记数组类型, optional和required都被去掉了

实际使用证明, required的设计确实是蛋疼, C++的调试版会弹出assert,release版和optional也没啥区别

map支持

map编写格式为

map<key_type, value_type> map_field = N;
例如:
map<string, Project> projects = 3;
代码生成确认支持map, 这对于很多语言来说又可以偷懒了

字段default标记不能使用了

位于proto2语法的字段number后的[default=XX]

这个东西不能用了, 理由是:

对于同一段序列化后的数据, 如果序列化端的default和反序列化端的default描述不一样会导致最终结果完全不一致

即: 同一个数据两个结果, 这是不可预测的结果, 因此干掉这个特性

不过本人觉得, 对于游戏来说, 这个功能本身可以压缩很多数据,虽然会有隐患

枚举默认值一定是0

proto2里的默认值是枚举的第一个value对应的值, 不一定为0

proto3在你定义value时, 强制要求第一个值必须为0

这个修改为避免隐患还是有帮助的

泛型描述支持

any类型, 可以代表任何类型, 可以先读进来, 再进行解析, 没具体用, 步子跨大了怕扯到蛋

支持json序列化

这个极好, json再次被同化了

增加了多种语言支持

js, objc, ruby, C#等等

然而, C#版本的基础runtime库是用C# 6.0的语法写的,这对于Unity mono祖传2.0来说, 确实扯到蛋了,没法用

Protobuf现在使用CMAKE做配置系统

编译起来稍微麻烦, 还要下个被墙掉的cmake…

第三方库里对于proto3的变化

Golang的官方protobuf支持: https://github.com/golang/protobuf


对于protocol buffer的初学者建议直接使用proto3。


使用protobufproto文件转换为js文件的过程可以通过以下步骤完成: 1. 首先,确保已经安装了npm和protobuf的相关库文件。可以使用以下命令进行安装: ``` npm install -g require npm install -g browserify npm install google-protobuf ``` 2. 下载proto.exe工具,并将其加入系统的环境变量中,或者将其放置在system32目录下。可以从以下链接中下载proto.exe工具: ``` https://github.com/protocolbuffers/protobuf/releases/download/v3.6.1/protoc-3.6.1-win32.zip ``` 3. 创建一个.proto文件,并在文件的第一行添加语法声明,例如: ``` syntax = "proto3"; package zhimpackage; message ZH_IMMessage { string field = 1; } ``` 4. 在命令行中运行以下命令,将.proto文件编译成js文件: ``` protoc.exe --js_out=import_style=commonjs,binary:. ZH_IM.proto ``` 5. 使用browserify工具将生成的js文件打包成一个文件。可以使用以下命令: ``` browserify ZH_IM.js > IMBody.js ``` 6. 现在,你可以将生成的IMBody.js文件用于前端页面了。在HTML文件中,引入IMBody.js文件: ```html <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>竹</title> <script src="IMBody.js"></script> </head> <body> </body> <script> var message = new proto.zhimpackage.ZH_IMMessage(); message.setField("一个人"); var bytes = message.serializeBinary(); console.log(bytes); var data = proto.zhimpackage.ZH_IMMessage.deserializeBinary(bytes); console.log(data); console.log(data.getField()); </script> </html> ``` 因此,以上步骤可以将protobufproto文件转换为js文件,并在前端页面中使用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Protobufproto js生成](https://blog.csdn.net/u010138825/article/details/85245995)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [javascript – protobuf.js将proto文件转换为JSON描述符,重复丢失](https://blog.csdn.net/weixin_29790897/article/details/115905577)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值