protocol buffers使用二进制传输格式传递消息,因此相比于xml,json来说要轻便很多。

示例:假设定义了一个Message

message Test1 {
required int32 a = ;
}

实际使用的时候将a设置为150,然后将其序列化到输出流,查看编码后的message,可以看到如下3个byte

  

解析:

上述三个字节实际分为两部分: 08  96 01。第一部分(08)包含了message成员变量的field number(a=1)和变量类型(Varint),第二部分(96 01)为a的实际值150。

这里面涉及几个概念:

  Varint:这个可以理解为可变长的int类型,数值越小使用的byte越少;

  field number和type:protocol buffer消息为一系列的key-value对。二进制版本的消息使用field number作为key。

当接收到一个message时,解析器可以忽略无法识别的字段,通过这样的方式,也可以在不影响老功能的前提下添加新的字段。 通信格式下的key实际包含2个值:.proto文件中的field number,和通信类型。通信类型如下

Type Meaning Used For
0 Varint int32, int64, uint32, uint64, sint32, sint64, bool, enum
1 64-bit fixed64, sfixed64, double
2 Length-delimited string, bytes, embedded messages, packed repeated fields
3 Start group groups (deprecated)
4 End group groups (deprecated)
5 32-bit fixed32, sfixed32, float

message流中的key类型为varint,计算方式为:(field_number << 3) | wire_type ,即后三位保存了通信类型

上述第一个字节为08,转化为二进制为0000 1000,没个varint的第一个比特位为MSB位,置位表示后续还有字节。去掉MSB位后为

 

后三位表示类型,值为0,表示类型为Varint;右移三位获取tag值为1(即message中设置的a = 1)

下面获取消息值150,注意:字节顺序为大端序

96 01 = 1001 0110  0000 0001
→ 000 0001 ++ 001 0110 (drop the msb and reverse the groups of 7 bits)
→ 10010110
→ 128 + 16 + 4 + 2 = 150

以上介绍的时varint的编码方式,下面介绍一下其他类型的编码

Signed integer

int32和int64的实际类型都是varint,当它表示负数的时候,为10个固定字节长度的值,效率比较低。可以使用sint32和sint64来表示有符号的数值,它采用ZigZag编码,编码对应关系如下,实际就是把负数从0开始做了扩展。

Signed Original Encoded As
0 0
-1 1
1 2
-2 3
2147483647 4294967294
-2147483648 4294967295

Non-Varint Numbers

非varint的值比较简单,double和fixed64的类型为1,表示64位固定长度的值;类似地,float和fixed32类型为5,表示固定32为长度的值,这两种情况下以小端序存储

Strings

类型为2,假设创建message如下,

message Test2 {
required string b = ;
}

实际消息b=“testing”

  74 65 73 74 69 6e 67

首字节为特殊字节:0001 0010,去除msb位:001 0010,后三位->10表示类型2,右移三位->10表示tag 2;07表示长度为7,74 65 73 74 69 6e 67为"testing"的值。

Embedded Messages

假设定义嵌入的message如下:

message Test3 {
required Test1 c = ;
}

设置Test1.c=150,获得的结果如下,可以看到后三个字节跟上述的一致

1a  08 96 01

Packed Repeated Fields

proto2中使用repeated field需要启用特殊选项[packed=true],在proto3中,默认启用packed。如果packed repeated field中包含0个元素,则它不会出现在被解析的message中。

message Test4 {
repeated int32 d = [packed=true];
}

编码如下:

        // tag (field number 4, wire type 2) ->0010 0,010
// payload size (6 bytes)
// first element (varint 3)
8E // second element (varint 270)
9E A7 // third element (varint 86942)

只有使用了原始数据类型(如32-bit或64-bit的varint)的repeated fields才能称之为"packed"

可以看到string,message,repeated field是有长度字段的,而varint由每个字节的msb位表示一个varint是否有后续字节

proto的类型定义如下:

.proto 说明 C++ Java Python Go Ruby C# PHP
double   double double float float64 Float double float
float   float float float float32 Float float float
int32 使用变长编码,对负数编码效率低,如果你的变量可能是负数,可以使用sint32 int32 int int int32 Fixnum or Bignum (as required) int integer
int64 使用变长编码,对负数编码效率低,如果你的变量可能是负数,可以使用sint64 int64 long int/long int64 Bignum long integer/string
uint32 使用变长编码 uint32 int int/long uint32 Fixnum or Bignum (as required) uint integer
uint64 使用变长编码 uint64 long int/long uint64 Bignum ulong integer/string
sint32 使用变长编码,带符号的int类型,对负数编码比int32高效 int32 int int int32 Fixnum or Bignum (as required) int integer
sint64 使用变长编码,带符号的int类型,对负数编码比int64高效 int64 long int/long int64 Bignum long integer/string
fixed32 4字节编码, 如果变量经常大于228228 的话,会比uint32高效 uint32 int int int32 Fixnum or Bignum (as required) uint integer
fixed64 8字节编码, 如果变量经常大于256256 的话,会比uint64高效 uint64 long int/long uint64 Bignum ulong integer/string
sfixed32 4字节编码 int32 int int int32 Fixnum or Bignum (as required) int integer
sfixed64 8字节编码 int64 long int/long int64 Bignum long integer/string
bool   bool boolean bool bool TrueClass/FalseClass bool boolean
string 必须包含utf-8编码或者7-bit ASCII text string String str/unicode string String (UTF-8) string string
bytes 任意的字节序列 string ByteString str []byte String (ASCII-8BIT) ByteString string

参考:Encoding

protocol buffers的编码原理的更多相关文章

  1. 理解netty对protocol buffers的编码解码

    一,netty+protocol buffers简要说明 Netty是业界最流行的NIO框架之一优点:1)API使用简单,开发门槛低:2)功能强大,预置了多种编解码功能,支持多种主流协议:3)定制能力 ...

  2. Protocol Buffers工作原理

    这里记录一下学习与使用Protocol Buffer的笔记,优点缺点如何使用这里不再叙述,重点关注与理解Protocol Buffers的工作原理,其大概实现. 我们经常使用Protocol Buff ...

  3. Protocol Buffers编码详解,例子,图解

    Protocol Buffers编码详解,例子,图解 本文不是让你掌握protobuf的使用,而是以超级细致的例子的方式分析protobuf的编码设计.通过此文你可以了解protobuf的数据压缩能力 ...

  4. Protocol Buffers(2):编码与解码

    目录 Message Structure 解码代码一窥 varint Protobuf中的整数和浮点数 Length-delimited相关类型 小结 参考 博客:blog.shinelee.me | ...

  5. google protocol buffer——protobuf的使用特性及编码原理

    这一系列文章主要是对protocol buffer这种编码格式的使用方式.特点.使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务. 在上一篇文章中,我们展示了 ...

  6. google protocol buffer——protobuf的编码原理二

    这一系列文章主要是对protocol buffer这种编码格式的使用方式.特点.使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务. 在上一篇文章中,我们主要通 ...

  7. 【笔记】直接使用protocol buffers的底层库,对特定场景的PB编解码进行处理,编码性能提升2.4倍,解码性能提升4.8倍

    接上一篇文章:[笔记]golang中使用protocol buffers的底层库直接解码二进制数据 最近计划优化prometheus的remote write协议,因为业务需要,实现了一个remote ...

  8. protocol buffers生成go代码原理

    本文描述了protocol buffers使用.proto文件生成pb.go文件的过程 编译器 编译器需要插件来编译环境,使用如下方式安装插件:go get github.com/golang/pro ...

  9. Google Protocol Buffers介绍

    简要介绍和总结protobuf的一些关键点,从我之前做的ppt里摘录而成,希望能节省protobuf初学者的入门时间.这是一个简单的Demo. Protobuf 简介 Protobuf全称Google ...

随机推荐

  1. ViewGroup onInterceptTouchEvent,ViewGroup onTouchEvent,View onTouchEvent执行顺序说明

    今天抽出了一些时间实践了viewgroup和view的触摸事件顺序,之前也试过,总是忘记,今天记下笔记说明一下 首先 onInterceptTouchEvent只会出现在viewgroup中,view ...

  2. queued frame 造成图形性能卡顿

    曾经遇到过卡顿是类似的原因:当时对显卡底层知识理解不懂,看到引擎底层有一个MaxFramexxx的接口,实现是使用注册表修改显卡底层的注册信息,当时还是一个掉接口习惯的客户端码农的思维,没理解底层含义 ...

  3. ORACLE EBS xml publisher 报表输出字符字段前部"0"被EXCEL自动去掉问题

    http://www.cnblogs.com/lzsu1989/archive/2012/10/17/2728528.html   Oracle  EBS 提供多种报表的开发和输出形式,由于MS Ex ...

  4. ORACLE报表触发器

    http://www.cnblogs.com/quanweiru/archive/2012/09/26/2704308.html 触发器一.报表触发器(report trigger)报表触发器主要用于 ...

  5. DevExpress中Tile Application窗体的模型架构图

    DEV中Tile Application模型架构比较复杂,整理一下和大家分享. 图中:立体代表类:虚线椭圆代表属性.

  6. Global.asax和HttpModule的执行顺序

    Application_Start-->用户自定义的HttpModule-->Application_BeginRequest   (注册->调用) 看到Init方法(在用户自定义的 ...

  7. sqlServer 查询表中31到40的记录,考虑id不连续的情况

    SQL   查询表中31到40的记录,考虑id不连续的情况 写出一条sql语句输出users表中31到40记录(数据库为SQL Server,以自动增长的ID作为主键,注意ID可能不是连续的)? -- ...

  8. JQuery Mobile - 解决切换页面时,闪屏,白屏等问题

    在点击链接,切换页面时候,总是闪屏,感觉很别扭,看起来不舒服,怎么解决这个问题?方法很简单,就是在每个页面的meta标签内定义user-scalable的属性为 no! <meta name=& ...

  9. Bootstrap框架(一)

    day57 参考:https://www.cnblogs.com/liwenzhou/p/8214637.html 下载:http://www.bootcss.com/   选择用于生产环境的 Boo ...

  10. Qt5学习笔记(基础)

    按钮 #include <QApplication> /*应用程序抽象类*/ #include <QWidget> //窗口类 #include <QPushButton ...