好奇的探索者,理性的思考者,踏实的行动者。
Table of Contents:
protobuf 是一个开源项目,而且是后台很硬的开源项目。
它是一种轻便高效的结构化数据存储格式,适合做数据存储或传输协议格式
性能好/效率高
Google公司为啥放着好端端的 XML 不用,非要另起炉灶,重新造轮子
XML格式化(序列化)的开销倒还好;但是 XML 解析(反序列化)的开销就不敢恭维
Google自然无法容忍XML在性能上的明显缺点。再加上 Google 从来就不缺造轮子的牛人,所以 protobuf 也就应运而生了
代码生成机制
一般来说,一个 message 结构会生成一个包装类
有了这种代码生成机制,开发人员再也不用吭哧吭哧地编写那些协议解析的代码了(干这种活是典型的吃力不讨好)
从某种意义上讲,可以把proto文件看成是描述通讯协议的规格说明书(或者叫接口规范)
支持“向后兼容”和“向前兼容”
所谓的【向后兼容】(backward compatible),就是说,当模块 B 升级了之后,它能够正确识别模块 A 发出的【老】版本的协议。由于老版本没有“状态”这个属性,在扩充协议时,可以考虑把“状态”属性设置成【非必填】的,或者给“状态”属性设置一个缺省值(如何设置缺省值,参见“这里”)。
所谓的【向前兼容】(forward compatible),就是说,当模块 A 升级了之后,模块 B 能够正常识别模块 A 发出的【新】版本的协议。这时候,新增加的“状态”属性会被忽略。
“向后兼容”和“向前兼容”有啥用捏?俺举个例子:
当你维护一个很庞大的分布式系统时,由于你无法【同时】升级【所有】模块,为了保证在升级过程中,整个系统不受影响(继续运转),就需要尽量保证通讯协议的“向后兼容”或“向前兼容”。
支持多种编程语言
官方支持好多语言,同时因为google社区的号召力,民间也搞了好多其他的语言版本
二进制格式导致可读性差
举个例子,比如通讯双方如果出现问题,极易导致扯皮(都不承认自己有问题,都说是对方的错)。俺对付扯皮的一个简单方法就是直接抓包并 dump 到日志文件,能比较容易地看出错误在哪一方。但是 protobuf 的二进制格式,导致你抓包并直接 dump 出来的 log 难以看懂。
另:protobuf提供了TextFormat这个工具类
缺乏自描述
一般来说,XML 是自描述的,而 protobuf 格式则不是。给你一段二进制格式的协议内容,如果不配合相应的 proto 文件,那简直就像天书一般。
由于“缺乏自描述”,再加上“二进制格式导致可读性差”。所以在“配置文件”方面,protobuf是肯定无法取代XML 的地位滴。
在 protobuf 的术语中,结构化数据被称为 Message
去官网下载protoc
bat生成脚本
示例1:
@echo off
if not exist ".\out" md out
echo start...
for %%i in (.\proto\*.proto) do (
echo %%i ok
.\bin\protoc.exe -I=.\proto --cpp_out=.\out %%i
)
echo end...
pause
示例2:
@echo off
set SOURCE_FOLDER=.
set CPP_COMPILER_PATH=protoc.exe
set CPP_TARGET_PATH=./client/
for /f "delims=" %%i in ('dir /b "%SOURCE_FOLDER%\*.proto"') do (
echo %CPP_COMPILER_PATH% --cpp_out=%CPP_TARGET_PATH% %%i
%CPP_COMPILER_PATH% --cpp_out=%CPP_TARGET_PATH% %%i
)
pause
在消息定义中,每个字段都有唯一的一个数字标识符。这些标识符是用来在消息的二进制格式中识别各个字段的,一旦开始使用就不能够再改变。注:[1,15]之内的标识号在编码的时候会占用一个字节。[16,2047]之内的标识号则占用2个字节。所以应该为那些频繁出现的消息元素保留 [1,15]之内的标识号。切记:要为将来有可能添加的、频繁出现的标识号预留一些标识号。