protocol buffers的编码原理

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

 

示例:假设定义了一个Message

message Test1 {
  required int32 a = 1;
}

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

08 96 01

 

解析:

上述三个字节实际分为两部分: 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,和通信类型。通信类型如下 

TypeMeaningUsed For
0Varintint32, int64, uint32, uint64, sint32, sint64, bool, enum
164-bitfixed64, sfixed64, double
2Length-delimitedstring, bytes, embedded messages, packed repeated fields
3Start groupgroups (deprecated)
4End groupgroups (deprecated)
532-bitfixed32, sfixed32, float

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

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

000 1000

后三位表示类型,值为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 OriginalEncoded As
00
-11
12
-23
21474836474294967294
-21474836484294967295

Non-Varint Numbers

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

Strings

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

message Test2 {
  required string b = 2;
}

实际消息b=“testing”

12 07 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 = 3;
}

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

1a 03 08 96 01

Packed Repeated Fields

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

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

编码如下:

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

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

 

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

 proto的类型定义如下:

.proto说明C++JavaPythonGoRubyC#PHP
double doubledoublefloatfloat64Floatdoublefloat
float floatfloatfloatfloat32Floatfloatfloat
int32使用变长编码,对负数编码效率低,如果你的变量可能是负数,可以使用sint32int32intintint32Fixnum or Bignum (as required)intinteger
int64使用变长编码,对负数编码效率低,如果你的变量可能是负数,可以使用sint64int64longint/longint64Bignumlonginteger/string
uint32使用变长编码uint32intint/longuint32Fixnum or Bignum (as required)uintinteger
uint64使用变长编码uint64longint/longuint64Bignumulonginteger/string
sint32使用变长编码,带符号的int类型,对负数编码比int32高效int32intintint32Fixnum or Bignum (as required)intinteger
sint64使用变长编码,带符号的int类型,对负数编码比int64高效int64longint/longint64Bignumlonginteger/string
fixed324字节编码, 如果变量经常大于228228 的话,会比uint32高效uint32intintint32Fixnum or Bignum (as required)uintinteger
fixed648字节编码, 如果变量经常大于256256 的话,会比uint64高效uint64longint/longuint64Bignumulonginteger/string
sfixed324字节编码int32intintint32Fixnum or Bignum (as required)intinteger
sfixed648字节编码int64longint/longint64Bignumlonginteger/string
bool boolbooleanboolboolTrueClass/FalseClassboolboolean
string必须包含utf-8编码或者7-bit ASCII textstringStringstr/unicodestringString (UTF-8)stringstring
bytes任意的字节序列stringByteStringstr[]byteString (ASCII-8BIT)ByteStringstring

 

参考:Encoding

转载于:https://www.cnblogs.com/charlieroro/p/9005033.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的公寓报修管理系统,源码+数据库+毕业论文+视频演示 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本公寓报修管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此公寓报修管理系统利用当下成熟完善的Spring Boot框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。公寓报修管理系统有管理员,住户,维修人员。管理员可以管理住户信息和维修人员信息,可以审核维修人员的请假信息,住户可以申请维修,可以对维修结果评价,维修人员负责住户提交的维修信息,也可以请假。公寓报修管理系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 关键词:公寓报修管理系统;Spring Boot框架;MySQL;自动化;VUE
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值