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. Tensorflow从源代码编译2

    https://blog.csdn.net/qq_37674858/article/details/81095101 https://blog.csdn.net/yhily2008/article/d ...

  2. (快速幂)Key Set--hdu--5363

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=5363 http://acm.hust.edu.cn/vjudge/contest/view.action ...

  3. Hdu2181 哈密顿绕行世界问题 2017-01-18 14:46 45人阅读 评论(0) 收藏

    哈密顿绕行世界问题 Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Sub ...

  4. 17、docker多机网络通信overlay

      理论上来说多台宿主机之间的docker容器之间是无法通讯的,但是多台宿主机之间的docker容器之间是可以通讯的,主要是通过VXLAN技术来实现的.   GitHub上对于docker-overl ...

  5. Fading Like a Flower

    Fading Like a Flower In a time where the sun descends alone 伴着落日孤独的脚步 I ran a long long way from hom ...

  6. 【TypeScript】TypeScript 学习 1——基本类型

    TypeScript 是 JavaScript 的超集,TypeScript 经过编译之后都会生成 JavaScript 代码.TypeScript 最大的特点就是类型化,因此才叫做 TypeScri ...

  7. ASP.NET MVC 富文本Ueditor编辑 后台传值前端乱码解决方案

    只是将当前内容String当成Html插入,我想是跟数据类型转换差不多 //把内容赋值给ueditor var ue = UE.getEditor('editor');//实例化 ue.ready(f ...

  8. 使用chosen插件实现多级联动和置位

    使用chosen插件实现多级联动和置位 首先写好第一个select,加上onchage属性之后,写onchange方法. <select data-placeholder="选择省份. ...

  9. Javascript/jQuery常用方法

    //字符串转成时间 function getDate(strDate) { var date = eval('new Date(' + strDate.replace(/\d+(?=-[^-]+$)/ ...

  10. Spring 开发第一步

    经过今天上午的学习发现spring上手开发一个"hello world"真的非常简单. 开发环境搭建: 1.去spring官网下载spring-framework-3.2.11.R ...