Protobuf学习

     公司现在大部分协议都使用protobuf的格式,protobuf协议数据冗余数据小、序列化和反序列化速度快,但它序列化的数据在传输过程中是不可理解的(不像xml或jason那样抓到了包就可以直接看到数据内容)。

     通过对protobuf的C++源码及python源码的一番简单阅读后,发现protobuf的序列化其实是个比较简单的过程。protobuf将数据分为6大类:

                          

        序列化后的数据,保存了每个字段的field_id、数据类型、数据内容(wiretype_length_delimited类型的数据还包含了一个数据内容的长度信息)这三个信息。field_id就是定义proto文件时,对每个字段定义的id数字,例如

           message Test {

                   fixed32 fixed32_id = 16;

            }

这个结构体中变量fixed32_id的field_id为2。一个字段序列化的格式如下:

           

浅绿色方块的内容只有当该字段的数据类型为wiretype_length_delimited时才有。可以看到序列化的数据分为三个数据块,field_id和数据类型放在同一个数据块中,数据长度在一个数据块中,数据内容放在一个数据块中。

        数据类型只有6种,3个bit就足够表示了,所以第一个数据块中数据的内容为:data1 = (filed_id << 3)  | (0x7 & 数据类型枚举值)。为了节约空间,protobuf并不是直接将data1写入到buffer中,而是采用了类似utf8的编码方式,每个byte只有后7个bit写数据,第一个bit用来表示下一个byte是否还属于这个数据块。例如:上述的Test结构体,只有一个字段,数据类型是wiretype_fiexed32,那么该字段的第一个数据块的内容则是 (16 << 3 ) | (0x7 & 5) =  0x85, 7个bit表示不了,所以至少需要两个byte, 第一个byte的值为 ((0x85 & 0x7f) | 0x80) = 0x85,第二个byte的值为 (0x85 >> 7) = 0x1。所以这里第一个数据块的数据就是两个字节:

             

由于uint32_id这个字段是wiretype_fiexed32类型,所以没有数据长度这个信息,数据内容是直接将fixed32_id这个字段的值按照32位整数的形式写入buffer,例如将结构体中fixed32_id赋值为1,则该结构体序列化后的数据为:

             

类似,如果数据类型是wiretype_fiexed64,则降数据按照64位整数的形式写入buffer。如果数据类型wiretype_varint,则数据内容的写入方式与第一个数据块类似,每个byte的第1个bit用来标志该数据是否结束,所以这里个人认为对于追求执行速度的程序,数据可以定义为fixed32、sfixed32、fixed64、sfixed64、float、double,这样序列化和反序列化省去”编码”过程,提高了执行速度,但对于存储和带宽是瓶颈的程序可以考虑将数据定义为int32、int64、uint32、uint64、sint32、sint64、bool、enum类型,类型对应表如下:

          

wiretype_length_delimited的数据比较特殊,它可以存放string、数组还可以存放一个自定义的message。当存放string类型的数据长度的数据块存放的是string的长度,数据内容数据块存放string的原始信息;当存放message的时候,数据长度的数据块存放的是message序列化为buffer后的长度,数据内容数据块存放message序列化为buffer后的内容。数据长度的写入方式跟wiretype_varint数据内容的写入方式一致。

 

参考:https://developers.google.com/protocol-buffers/docs/encoding

时间: 2025-01-02 21:48:10

Protobuf学习的相关文章

google protobuf学习笔记一:windows下环境配置

欢迎转载,转载请注明原文地址:http://blog.csdn.net/majianfei1023/article/details/45371743 protobuf的使用和原理,请查看:http://blog.csdn.net/majianfei1023/article/details/45112415 Windows下google protobuf开发环境配置 最近项目需求,Client与Server的网络通信协议传输使用google protobuf rpc.对于Protobuf,以前是只

protobuf学习资料整理

最近准备使用protobuf, 整理一下比较好的学习资料. 1. 官方文档: https://developers.google.com/protocol-buffers 有些内容是基于proto3的, 大部分情况下proto2也都适用 2. IBM developworks的入门文章: http://www.ibm.com/developerworks/cn/linux/l-cn-gpb/ 3. 淘宝搜索技术博客的文章, 重点介绍protobuf的反射和自描述: http://www.sear

protobuf 学习笔记

它是什么 术语定义 protocol buffer 官网github定义:https://github.com/google/protobuf https://developers.google.com/protocol-buffers/  开发者帮助 百度百科定义:http://baike.baidu.com/link?url=vlbJtV9p9Vfj4wQDif_XaNymBZI67u3AFjF5ZpT6iJjOwGfsenwUZMieBGrtlUC0FkWwWQic-Y3rwXYP0tq9

golang Protobuf学习

protobuf是一种高效的数据传输格式(Google's data interchange format),且与语言无关,protobuf和json是基于http服务中最常见的两种数据格式.今天来学习基于golang的protobuf相关内容. google protocol buffer: https://developers.google.com/protocol-buffers/golang 官方提供的protobuf支持插件:https://github.com/golang/prot

protobuf 学习 收藏的文章

Protobuf数据格式解析: packed repeated与repeated的区别在于编码方式不一样,repeated将多个属性类型与值分开存储.而packed repeated采用Length-delimited方式. proto3的repeated默认就是使用packed这种方式来存储,(proto2与proto3区别在于.proto的语法). http://blog.csdn.net/zhaozheng7758/article/details/6749000: [packed =fal

google protobuf学习笔记一:使用和原理

一.什么是protobuf protobuf全称Google Protocol Buffers,是google开发的的一套用于数据存储,网络通信时用于协议编解码的工具库.它和XML或者JSON差不多,也就是把某种数据结构的信息,以某种格式(XML,JSON)保存起来,protobuf与XML和JSON不同在于,protobuf是基于二进制的.主要用于数据存储.传输协议格式等场合.那既然有了XML等工具,为什么还要开发protobuf呢?主要是因为性能,包括时间开销和空间开销: 1.时间开销:XM

protobuf学习------ubuntu14.04下protobuf2.6安装

1 下载protobuf https://github.com/google/protobuf/releases/download/v2.6.1/protobuf-2.6.1.tar.gz 2  进入下载文件的目录 1 tar -zxvf protobuf-2.6.1.tar.gz 2 cd protobuf-2.6.1/ 3 ./configure 4 make 5 make check 6 sudo make install 我在执行./configure时出现如下问题 Ubuntu: co

protobuf 学习 (转载)

1.下载地址:https://code.google.com/p/protobuf/downloads/list 安装 ./configure && make && make install 2.试执行 protoc 命令,如果提示链接库错误,则执行 ldconfig 3.编译 .proto 文件成 C++ 头文件和源文件 protoc Login.proto --cpp_out=. 注:可以使用 protoc *.proto --cpp_out=. 批量编译多个 prot

Sword protobuf学习二

编写protobuf消息文件 文件格式: xxx.proto //标明使用哪个版本的protobuf,默认2.0版本 syntax = "proto3"; //类似于c++中的namespace package commun; //message类首字母需要大写,message类中所有的成员属性最好全部小写,因为在赋值时,protobuf提供的方法名字全部是小写的 message Say{ //字段规则移除了"required",并把"optional&q