一个轻量的 wire format 解释器(google protobuf 的二进制格式)
程序员文章站
2022-07-14 14:13:19
...
google 的 protobuf 项目,底层的二进制格式设计很精简,格式的详细描述参考下面的链接:
http://code.google.com/apis/protocolbuffers/docs/encoding.html
下载链接
http://spjson.googlecode.com/files/spjson-0.3.src.tar.gz
暂时是作为 spjson 的一部分。
这个格式被 google 才称为 wire format ,实质是一个用于保存 key/value 对的二进制格式。
key 被称为 fieldNumber 。
value 分为几种类型:varint,64bit,32bit,Length-delimited 。
varint 是指变长整数,实质上可能对应 int8,int16,int32,int64 和他们的有符号类型。varint 对于保存小整数有非常好的压缩效果,对于 <= 128 的整数只需要一个字节。具体的算法可以参考上面的链接。
64bit 和 32bit 按我的理解主要可能是用于映射 double 和 float 。因为整数本身已经全部可以通过 varint 来解决了。 把 double 和 float 按 little-endian byte order 进行保存。
Length-delimited 用于保存字符串和二进制数据。二进制数据可能是另外一个 protobuf ,这样就可以实现支持内嵌复杂类型的功能。
实现用典型的 codec 的方式来实现,一个 encoder 和一个 decoder 。
encoder 对于不同的类型,提供了对应的 add 方法。在任何时候,都可以调用 encoder 的 getBuffer 和 getSize 获取当前已经生成的 buffer 。
decoder 提供 getNext 和 find 两个方法。getNext 用于遍历 protobuf 的所有字段。find 方法用于根据 fieldNumber 来获取对应的字段。定义了一个辅助数据结构 KeyValPair_t 来简化这个两个方法的参数。find 方法内部使用二分查找法来加速。
http://code.google.com/apis/protocolbuffers/docs/encoding.html
下载链接
http://spjson.googlecode.com/files/spjson-0.3.src.tar.gz
暂时是作为 spjson 的一部分。
这个格式被 google 才称为 wire format ,实质是一个用于保存 key/value 对的二进制格式。
key 被称为 fieldNumber 。
value 分为几种类型:varint,64bit,32bit,Length-delimited 。
varint 是指变长整数,实质上可能对应 int8,int16,int32,int64 和他们的有符号类型。varint 对于保存小整数有非常好的压缩效果,对于 <= 128 的整数只需要一个字节。具体的算法可以参考上面的链接。
64bit 和 32bit 按我的理解主要可能是用于映射 double 和 float 。因为整数本身已经全部可以通过 varint 来解决了。 把 double 和 float 按 little-endian byte order 进行保存。
Length-delimited 用于保存字符串和二进制数据。二进制数据可能是另外一个 protobuf ,这样就可以实现支持内嵌复杂类型的功能。
实现用典型的 codec 的方式来实现,一个 encoder 和一个 decoder 。
class SP_ProtoBufEncoder { public: SP_ProtoBufEncoder( int initLen = 0 ); ~SP_ProtoBufEncoder(); int addVarint( int fieldNumber, uint64_t value ); int addDouble( int fieldNumber, double value ); int addFloat( int fieldNumber, float value ); int addBinary( int fieldNumber, const char * buffer, int len ); const char * getBuffer(); int getSize(); }; class SP_ProtoBufDecoder { public: SP_ProtoBufDecoder( const char * buffer, int len ); ~SP_ProtoBufDecoder(); bool getNext( KeyValPair_t * pair ); bool find( int fieldNumber, KeyValPair_t * pair, int index = 0 ); };
encoder 对于不同的类型,提供了对应的 add 方法。在任何时候,都可以调用 encoder 的 getBuffer 和 getSize 获取当前已经生成的 buffer 。
decoder 提供 getNext 和 find 两个方法。getNext 用于遍历 protobuf 的所有字段。find 方法用于根据 fieldNumber 来获取对应的字段。定义了一个辅助数据结构 KeyValPair_t 来简化这个两个方法的参数。find 方法内部使用二分查找法来加速。
上一篇: DWR源码学习