解Google-ProtoBuf中结构化数据的编码

Protobuf编码规则详 Protobuf 编码 阅读详情

 

本文的主要内容是google protobuf中序列化数据时用到的编码规则,但是,介绍具体的编码规则之前,我觉得有必要先简单介绍一下google protobuf。因此,本文首先会介绍一些google protobuf相关的内容,让读者朋友对google protobuf有一个初步的印象,然后,再开始进入正题—-深入浅出地介绍google protobuf中用到的编码规则。下面言归正传,开始今天的话题。

1. Google-ProtoBuf是什么

ProtoBuf,全称是Protocol Buffers, 它是谷歌内部用的一种高效的、可扩展的对结构化数据进行编码的格式规范。谷歌自己内部很多程序之间的通信协议都用了ProtoBuf。

ProtoBuf可以支持多种编程语言,目前已经C++, Java和Python,本文中所前的内容用到例子的话,会以C++为例。

2.如何得到Google-ProtoBuf

ProtoBuf在Google Code上的主页是:http://code.google.com/p/protobuf/, 感兴趣的朋友可以在这里下载ProtoBuf的源码,也可以在这里阅读ProtoBuf的详细的文档。

 

3. 深入浅出Google-ProtoBuf中的编码规则

(1)序列化和反序列化:

在开始本部分的内容之前,首先有必要介绍两个基本概念,一个是序列化,一个是反序列化。这两个概念的定义在网上搜一下都很多的,但大多都讲得比较晦涩,不太好理解,在这里我会用比较通俗的文字来解释,尽可能让读都朋友们一读就明白是怎么回事:

序列化:是指将结构化的数据按一定的编码规范转成指定格式的过程

反序列化:是指将转成指定格式的数据解析成原始的结构化数据的过程

举个例子,Person是一个表示人的对象类型,person是一个Person类型的对象,将person存到一个对应的XML文档中的过程就是一种序列化,而解析XML生成对应Person类型对象person的过程,就是一个反序列化的过程。在这里结构化数据指的就是Person类型的数据,一定的编码规范指的就是XML文档的规范。XML是一种简单的序列化方式,用XML序列化的好处是,XML的通用性比较好,另外,XML是一种文本格式,对人阅读比较友好,但是XML方式比较占空间,效率也不是很高。通常,比较高效的序列化都是采用二进制方式的,将要序列化的结构化数据,按一定的编码规范,转成为一串二进制的字节流存储下来,需要用的时候再从这串二进制的字节流中反序列化出对应的结构化的数据。

通过上面的介绍,我们给protobuf下一个比较正式的定义了:Google ProtoBuf是Google制定的一种用来序列化结构化数据的程序库。

(2)ProtoBuf中的编码:

1) ProtoBuf编码基础——Varints, varints是一种将一个整数序列化为一个或者多个Bytes的方法,越小的整数,使用的Bytes越少。

Varints的基本规则是:

(a) 每个Byte的最高位(msb)是标志位,如果该位为1,表示该Byte后面还有其它Byte,如果该位为0,表示该Byte是最后一个Byte。

(b)每个Byte的低7位是用来存数值的位

(c)Varints方法用Litte-Endian(小端)字节序

举个例子:300用Varints序列化的结果是1010 1100 0000 0010,运算过程如下 所示:

1010 1100 0000 0010->010 1100 000 0010(去标志位)->

000 0010 010 1100(调整字节序)-> 1 0010 1100 ->256+32+8+4=300(计算值)

2)ProtoBuf中消息的编码规则:

(a)每条消息(message)都是有一系列的key-value对组成的, key和value分别采用不同的编码方式。

(b)对某一条件消息(message)进行编码的时候,是把该消息中所有的key-value对序列化成二进制字节流;而解码的时候,解码程序读入二进制的字节流,解析出每一个key-value对,如果解码过程中遇到识别不出来的类型,直接跳过。这样的机制,保证了即使该消息添加了新的字段,也不会影响旧的编/解码程序正常工作。

(c)key由两部分组成,一部分是在定义消息时对字段的编号(field_num),另一部分是字段类型(wire_type)。字段类型定义如下表所示。

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

(d)key的编码方式:field_num << 3 | wire_type

(e)varint类型(wire_type=0)的编码,与第(1)部分中介绍的方法基本一致,但是int32, int64和sint32,sint64有些特别之处:int32和int64就是简单的按varints方法来编码,所以像-1、-2这样负数也会占比较多的Bytes。于是sint32和sint64采用了一种改进的方法:先采用Zigzag方法将所有的整数(正数、0和负数)一一映射到所有的无符号数上,然后再采用varints编码方法进行编码。Zigzag映射函数为:

Zigzag(n) = (n << 1) ^ (n >> 31),  n为sint32时

Zigzag(n) = (n << 1) ^ (n >> 63),  n为sint64时

下表是一个比较直观的映射表,这样映射后再进行编码的好处就是绝对值比较小的负数序列化后的结果占的Bytes数也会比较少。

Signed OriginalEncoded As
00
-11
12
-23
24
-35
21474836474294967294
-21474836484294967295

(f)64-bit(wire_type=1)和32-bit(wire_type=5)的编码方式就比较简单了,直接在key后面跟上64bits或32bits,采用Little-Endian(小端)字节序。

(g)length-delimited(wire_type=2)的编码方式:key+length+content, key的编码方式是统一的,length采用varints编码方式,content就是由length指定的长度的Bytes。

(h)wire_type=3和4的现在已经不推荐使用了,因此这里也不再做介绍。

3)ProtoBuf编解码中字段顺序(Field order)的问题:

(a) 编码/解码与字段顺序无关,这一点由key-value机制就能保证

(b)对于未知的字段,编码的时候会把它写在序列化完的已知字段后面。

 

从零到一:AIGC+Unity3D打造动态天空盒的实战指南 本文详细介绍了如何利用AIGC技术结合Unity3D打造动态天空盒的实战指南。通过AIGC生成360全景图,再集成到Unity3D中,实现高效、多样化的天空盒效果。文章涵盖了从AIGC全景图生成、工作流搭建到Unity场景集成的完整流程,并提供了代码示例和优化建议,帮助开发者快速掌握这一技术。 阅读详情

相关推荐

Android 14.0 首次开机默认授予app运行时权限(去掉运行时授权弹窗)

在14.0的系统rom产品定制化开发中,在6.0以后对于权限的申请,都需要动态申请,所以会在系统首次启动后,在app的首次运行时, 会弹出授权窗口,会让用户手动授予app运行时权限,在由于系统产品开发需要要求默认授予app运行时权限,不需要用户默认授予运行时弹窗,所以需要在首次开机默认授予所有app运行时权限

安卓兼职framework和app工程师的博客 2496

Protobuf 学习手册——编码

一、编码规范 Google 官方提供了 Protobuf编码规范,通过遵循这些规范,可以使 Protobuf 消息定义及其相应的类保持一致并易于阅读。 Protobuf 编码规范可能随着时间推移而发生变化,对于既有项目,应当保持编码规范的一致性,而不需盲目保持最新的编码规范。但是对于全新项目,应当遵循官方的编码规范,可以点击这里查阅官方最新的编码规范。 1.1 Override 一行不超过 ...

Jitwxs 2307

neo4j-community-5.26.0-windows

Neo4j是一个高性能的NoSQL图形数据库,它将数据存储为节点之间的关系网,而非传统的关系型数据库的表格形式。这种图形存储方式使得Neo4j特别适合处理复杂的关系和连接查询,尤其适用于社交网络、推荐系统、网络拓扑和知识图谱等领域。neo4j-community-5.26.0版本是Neo4j数据库的一个社区版发布,这是面向开发者和小型团队的免费版本,提供了一个完整的图形数据库功能,可以用于非生产环境。社区版与企业版的主要区别在于支持的规模、性能优化以及一些高级功能的限制。文件名称"neo4j-community-5.26.0-windows"暗示了这是一个专为Windows操作系统设计的安装包。这意味着用户可以在Windows平台上直接安装和运行Neo4j社区版,无需担心操作系统兼容性问题。这对于Windows用户来说是一个好消息,因为它大大简化了部署过程。Neo4j社区版5.26.0版本可能包含了多个组件,如数据库核心、Web管理界面以及Cypher查询语言的支持。Cypher是Neo4j的官方查询语言,用于图形数据的创建、读取、更新和删除操作,它是Neo4j中进行图形查询和管理的基石。在使用Neo4j时,用户会发现其安装过程相比于其他数据库要简洁很多,通常只需下载安装文件,压并运行即可。安装完成后,Neo4j会自动启动一个内置的Web管理界面,通过这个界面用户可以进行数据库的管理、监控和查询操作。此外,Neo4j社区版还提供了多种驱动程序和API,方便用户在不同的编程语言环境下访问和操作数据库。不过,需要注意的是,尽管社区版可以满足许多使用场景,但企业版拥有更多的特性,包括但不限于高可用性集群、在线备份、企业级安全特性以及专业的技术支持。对于那些需要大规模部署和高性能要求的用户来说,企业版可能是一个更好的选择。在标签方面,"NEO4J"标签表明

ProtoBuf中的编码

http://blog.csdn.net/y_xianjun/article/details/9046789

aalbertini的专栏 1072

Google Protocol Buffer 传输数据相对其他格式较短的原理

封包格式,减少数据传输量

526

protobuf

protobuf码规则示例

eo_rsgfd的博客 2275

protobuffer 中文乱码

protobuffer使用参看网络文档,此处说明如何决属性中文乱码问题 1,构建时,用utf8统一转码 CMsg msg = CMsg.CreateBuilder() .SetMsgcheck(head.ToByteString().ToStringUtf8()) .SetMsgstude...

jackymin的专栏 5523

Google-ProtoBuf数据编码

Google-ProtoBuf数据编码 本文的主要介绍google protobuf中序列化数据时用到的编码规则。 1. Google-ProtoBuf是什么 ProtoBuf,全称是Protocol Buffers, 它是谷歌内部用的一种高效的、可扩展的对结构化数据进行编码的格式规范。谷歌自己内部很多程序之间的通信协议都用了ProtoBufProtoBuf可以支持多种编程语言,目

luxiaoyu_sdc的专栏 3065

ProtoBuf结构化数据编码

本文的主要内容是google protobuf中序列化数据时用到的编码规则,但是,介绍具体的编码规则之前,我觉得有必要先简单介绍一下google protobuf。因此,本文首先会介绍一些google protobuf相关的内容,让读者朋友对google protobuf有一个初步的印象,然后,再开始进入正题—-深入浅出地介绍google protobuf中用到的编码规则。下面言归正传,开始今天的...

lizhibing115的博客 525

Google开源协议Protobuf的简介及其序列化原理

protobuf介绍及其序列化原理什么是probobuf、作用是什么:   Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。protobuf协议是以一个 .pro

Chengzi_comm的专栏 3万+

Google-ProtoBuf结构化数据编码

本文的主要内容是google protobuf中序列化数据时用到的编码规则,但是,介绍具体的编码规则之前,我觉得有必要先简单介绍一下google protobuf。因此,本文首先会介绍一些google protobuf相关的内容,让读者朋友对google protobuf有一个初步的印象,然后,再开始进入正题—-深入浅出地介绍google protobuf中用到的编码规则。下面言归正传,开始今天的

把梦想放飞在蓝色的天空里... 2637

[C++][ProtoBuf][初识ProtoBuf]详细讲

[C++][ProtoBuf][初识ProtoBuf]详细讲

SnowK博客 4485

GoogleProtobuf, 快就完事啦

例如,可以通过将公共字段放在一个单独的消息中,然后将这个消息作为另一个消息的字段来实现类似于类继承的功能。总之,在 Spring Boot 中使用 Protobuf 作为 Redis 的序列化和反序列化工具可以提高应用程序的性能和可扩展性。然而,在实际应用中,您可以通过上述方式在 Protobuf 中表示嵌套类、集合以及类似于类继承和接口实现的概念。在 Spring Boot 中使用 Protobuf 作为 Redis 的序列化和反序列化工具,首先需要添加相关的依赖,然后配置 RedisTemplate。

洪晓鸿 3252

Protobuf 编码及序列化的记录

工作中用到了protobuf,然后之前在面试的时候面试官就问了一个问题,如果将int32类型的字段的值设置为0,那还会将该值进行序列化吗?当时是懵了的,因为自己还没有研究这部分。当时给的结果是不会,猜测protobuf中int32的默认值是0,既然默认值是0的,那应该就不会进行序列化了。 那次面试之后就觉得自己应该了一下这部分了,结果这两天了完之后,发现自己猜错了。好记...

u014209688的专栏 7435

ProtoBuf 编码

在对 ProtoBuf 做了一些基本介绍之后,这篇开始进入正题,深入 ProtoBuf 的一些原理,让我们看看 ProtoBuf 是如何尽其所能的压榨编码性能和效率的。 编码结构 TLV 格式是我们比较熟悉的编码格式。 所谓的 TLV 即 Tag - Length - Value。Tag 作为该字段的唯一标识,Length 代表 Value 数据域的长度,最后的 Value 便是数据本身。 ProtoBuf 编码采用类似的结构,但是实际上又有较大区别,其编码结构可见下图: 们来一步步析.

pocher的博客 4149

protobuf:字符编码

repeatedlastrepeated通常,一个编码的消息永远不会有一个以上的非重复字段实例。然而,析器应该处理它们这样做的情况。对于数字类型和字符串,如果同一个字段多次出现,析器会接受它看到的最后一个值。对于嵌入的消息字段,析器会合并同一字段的多个实例,就像使用message::MergeFrom方法一样——也就是说,后一个实例中的所有奇异标量字段都会替换前一个实例,奇异嵌入消息会被合并,重复字段会被连接。

aggs1990的专栏 1016

Protobuf 编码规则及c++使用详

包含了常用的整形,字符串,枚举,结构体,repeated(数组)类型。

weixin_36623563的博客 1672

protobuf优缺点及编码原理

proto消息类型文件一般以.proto结尾,可以在一个.proto文件中定义一个或多个消息类型。下面是一个搜索查询的消息类型定义,在最开头的 syntax 描述的是版本信息,proto 目前有两个版本 proto2 和 proto3。明确的设置了语法格式为 proto3,如果不设置syntax即默认为 proto2。query为要查询的内容,表示查询有多少页,每页的数量为 result_per_page 个。必须位于.proto文中除去注释和空行的第一行。

谢谢大家的关注 1208

Protobuf 消息 dotnet-grpc

Protobuf消息定义中的每个字段都有一个唯一的编号。 消息序列化为 Protobuf 时,字段编号用于标识字段。 序列化一个小编号比序列化整个字段名称要快。列举了与dotnet类型对应关系

qq_35100531的博客 410
上一篇: 采用epoll模型服务器连接管理器实现
下一篇: 无锁(lock-free)数据结构
nellson
博客等级 码龄20年 48粉丝 84原创
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值