pbc的proto3接入
Protobuf 的 proto3发布也有挺长一段时间了。现在很多新项目慢慢转变用proto3来开发。这篇文章主要记录一下我在给pbc写对proto3支持时的一些信息,也许对其他童鞋也有点助益。抛砖引玉一下。
简介
pbc是云风开发的一个纯C的读写protobuf的很小巧的库,配合上它提供的lua-5.1和lua-5.3的binding可以很容易地在lua里完成对pb文件的注册和打解包。应该很多人都知道这个组件。
但是后来云风自己又发明了个sproto,然后主推在他的skynet框架中使用sproto,于是pbc就不再有功能维护了。
我们之前的也尝试直接使用了proto3,也是因为在迁移期,所以并没有使用全部的特性。但是仍然有一些向前不兼容的细节需要处理一下,所以有了这个改造
Proto2和Proto3的差异
因为主要目的是兼容,所以下面会列出proto3得不同之处,并且会标注处理方法。
移除unknown fields(据说以后会加回来)
这里主要影响更新以后客户端和服务器版本不一致得时候得数据处理。本身游戏逻辑在协议设计得时候就会考虑这个问题,如果非强制更新,会允许缺失或者忽略一些数据。所以本身影响不大。
移除extension,增加Any类型代替
同样,目前我还没有用到过这个特性。也暂时忽略。
枚举类型语义变更,现在必须提供默认值
这个影响proto文件得语法,这个对proto文件得改造量有点大。但对pbc也没什么影响。
官方支持json格式和检查utf-8编码
这个就是方便一点,以前我们自己写过一个protobuf到json得中间件。另外很多protobuf得代码里写死了UTF-8。所以加个检查也是对得。对兼容性也没啥影响。
不再支持Group
这个我一直觉得很鸡肋,去掉也好。
所有数字类型的repeated字段现在默认是packed=true的了。
protobuf的repeated字段有两种处理方式:第一种是由多个key-value对组成,也就是说repeated的数据中,key可能会出现多次;第二种是先有一个varint,表示个数,后面跟N个value。具体编码可以参见我以前写得 《理解Protobuf的数据编码规则》。前一种就是packed=false,反之后一种就是packed=true。这里会影响解包时的组织结构,所以是一个需要修改pbc的地方。
C++ API的重要更新:允许自定义内存分配区
其他语言的我没看,C++的众多变化里我也就觉得这一个比较重要。这是可以自定义内存分配区。因为以前protobuf的message的嵌套结构,都是new出来的。估计是这样多了以后内存碎片和分配性能都比较受影响吧,所以多了这么个类似内存池的东西。感觉还是蛮有用的。虽然我一直用jemalloc所以也不太care这个malloc的开销(只要别乱搞,这里的分配开销和逻辑比任然是九牛一毛)。
大体上差异就这么多了,当然后面的版本会再有些修订也未可知。但是总体看来,要做到打解包的兼容性适配,只有移除需要改的地方,就是repeated字段那里。其他的也就是proto文件的语法有些变化,其他的都还兼容。
pbc改造
涉及的代码就一个文件: register.c,改成如下的样子。
注释里写得比较清楚了。就不再复述了。
有个题外话,我之前写得转表工具[xresloader][8]也很早就接入了proto3,这个工具里已经用proto3了。但是sample里同时提供了proto_v2和proto_v3的示例。这个pbc首先是用来读这里的转表工具的转出数据的。当然用老版本的pbc也可以,就是所有的数字得显式指定packed属性。
BTW
因为顺便要给客户端用,之前手动打iOS和android的包麻烦了点。而且有些为了省事是直接工程导入的,自动构建上很麻烦。所以这次干脆写了个基于cmake的一键打包到iOS和Android的静态库或动态库的脚本,放在根目录下build_android.sh和build_ios.sh。如果要编译lua-binding,则需要指定一下lua-5.1或者lua-5.3的包含目录,android的动态库还需要指定下客户端所使用的lua库目录,反正所有都写在README.md里了。
最后,所有完成的修改都放在了 https://github.com/owent-contrib/pbc/tree/proto_v3 里。这个适配只是做了兼容性适配,最好当然还是实现那些proto3的新数据结构啦。而且这个proto_v3的分支我并没有创建PR推回去。但是前面提到的Android和iOS脚本我Push回去了,云风Merge了第一版,第二版暂时还没Merge。第二版只不过是环境检测和兼容性上的一些优化罢了。
Last updated