Protobuf的简单介绍、使用和分析
bigegpt 2024-11-24 11:59 3 浏览
一、protobuf是什么?
protobuf(Google Protocol Buffers)是Google提供一个具有高效的协议数据交换格式工具库(类似Json),但相比于Json,Protobuf有更高的转化效率,时间效率和空间效率都是JSON的3-5倍。后面将会有简单的demo对于这两种格式的数据转化效率的对比。但这个库目前使用还不是太流行,据说谷歌内部很多产品都有使用。
二、protobuf有什么?
Protobuf 提供了C++、java、python语言的支持,提供了windows(proto.exe)和linux平台动态编译生成proto文件对应的源文件。proto文件定义了协议数据中的实体结构(message ,field)
关键字message: 代表了实体结构,由多个消息字段(field)组成。
消息字段(field): 包括数据类型、字段名、字段规则、字段唯一标识、默认值
数据类型:常见的原子类型都支持(在FieldDescriptor::kTypeToName中有定义)
字段规则:(在FieldDescriptor::kLabelToName中定义)
required:必须初始化字段,如果没有赋值,在数据序列化时会抛出异常
optional:可选字段,可以不必初始化。
repeated:数据可以重复(相当于java 中的Array或List)
字段唯一标识:序列化和反序列化将会使用到。
默认值:在定义消息字段时可以给出默认值。
三、protobuf有什么用?
Xml、Json是目前常用的数据交换格式,它们直接使用字段名称维护序列化后类实例中字段与数据之间的映射关系,一般用字符串的形式保存在序列化后的字节流中。消息和消息的定义相对独立,可读性较好。但序列化后的数据字节很大,序列化和反序列化的时间较长,数据传输效率不高。
Protobuf和Xml、Json序列化的方式不同,采用了二进制字节的序列化方式,用字段索引和字段类型通过算法计算得到字段之前的关系映射,从而达到更高的时间效率和空间效率,特别适合对数据大小和传输速率比较敏感的场合使用。
四、Protobuf在Android上的使用
1、创建proto文件,定义消息的实体结构
2、编译proto文件生成对应的java文件
3、添加protobuf-java-2.5.0.jar到android工程
4、在android中实现对消息结构的序列化/反序列化
五、Protobuf与json的对比
1、创建product.proto文件
定义了三个Message(ProductInfo、PhoneInfo、Watch)消息结构
2、消息结构对应的java类(ProductInfo、PhoneInfo、Watch)
图片上传失败
3、消息结构和java对象赋值
PhoneName:” idol3”
Price:2000
Top:1
WatchName:” tcl watch”
Price:1000
Top:1
4、JSON字符串
{"phone":{"phoneName":"idol3","price":2000,"top":1},"watch":{"watchName":"tcl wtch","top":1,"price":1000}}
5、Protobuf转化后的二进制文件
空间效率
Json:107个字节
Protobuf:32个字节
时间效率
Json序列化: 1ms , 反序列化:0ms
Protobuf 序列化: 0ms 反序列化:0ms
将public List<Phone> list和repeated PhoneInfo phoneInfoList =3;都赋值为1000个PhoneInfo
空间效率
Json:4206个字节
Protobuf:1332个字节
时间效率
Json序列化: 4ms , 反序列化:1ms
Protobuf 序列化: 1ms 反序列化:0ms
六、protobuf的简单分析
1、优缺点
优点:通过以上的时间效率和空间效率,可以看出protobuf的空间效率是JSON的2-5倍,时间效率要高,对于数据大小敏感,传输效率高的模块可以采用protobuf库
缺点:消息结构可读性不高,序列化后的字节序列为二进制序列不能简单的分析有效性;目前使用不广泛,只支持java,C++和Python;
2、数据序列化/反序列化
a、规则:
protobuf把消息结果message也是通过 key-value对来表示。只是其中的key是采取一定的算法计算出来的即通过每个message中每个字段(field index)和字段的数据类型进行运算得来的key = (index<<3)|type;
type类型的对应关系如下:
Value会根据数据类型的不同会有两种表现形式:
对于各种int,bool,enum类型,value就是Varint
对于string,bytes,message等等类型,value就是length+原始内容编码
Varints是一种紧凑表示数字的方法。它用一个或者多个字节表示一个数字,值越小的数字字节数越少。相对于传统的用4字节表示int32类型数字,Varints对于小于128的数值都可以用一个字节表示,大于128的数值会用更多的字节来表示,对于很大的数据则需要用5个字节来表示。
Varints算法描述: 每一个字节的最高位都是有特殊含义的,如果是1,则表示后续的字节也是该数字的一部分;如果是0,则结束
b、demo生成的的二进制文件反序列化。
第1个字节 (0A)
字段索引(index): 0A = 0001010 0A>>3 = 001 = 1
数据类型(type): 0A = 0001010&111 = 2 (String);
第2个字节 (0C)
字符串长度(length): 0E = 12;
字符串: 0A 05 69 64 6F 6C 33 10 01 18 BD 0F
第3个字节 (0A)
因为字符串是来自phoneInfo属于嵌套类型
字段索引(index): 0A = 0001010 0A>>3 = 001 = 1
数据类型(type): 0A = 0001010&111 = 2 (String);
第4-9个字节(69 64 6F 6C 33)
字符串长度(length): 05 = 5
字符串: 69 64 6F 6C 33 = idol3
第10个字节 (10)
字段索引(index): 10 = 00010000 10A>>3 = 0010 = 2
数据类型(type): 10 = 00010000&111 = 0 (Varints);
第11个字节 (01)
Varints: 01 = 00001字节的最高位为0 整数结束
Value: 1;
第12个字节(18)
字段索引(index): 18 = 00011000 18>> 00011 = 3
数据类型(type): 18 = 00011000&111 = 0 (Varints);
第13个字节(D0)
最高位为1,整数计算到下一个字节
第14个字节(0F)
最高位为0,整数计算结束
Value:为11111010000 =2000
领取C++音视频开发学习资料:点击→音视频开发(资料文档+视频教程+面试题)(FFmpeg+WebRTC+RTMP+RTSP+HLS+RTP)
C、反序列化结果
phoneinfo为:
phoneName = “idol3”
top = 1
price = 2000;
同样的方法watchInfo为:
watchName = “tcl name”
top = 1
price=2000
3、时间效率
通过protobuf序列化/反序列化的过程可以得出:protobuf是通过算法生成二进制流,序列化与反序列化不需要解析相应的节点属性和多余的描述信息,所以序列化和反序列化时间效率较高。
4、空间效率
xml、json是用字段名称来确定类实例中字段之间的独立性,所以序列化后的数据多了很多描述信息,增加了序列化后的字节序列的容量。
Protobuf的序列化/反序列化过程可以得出:
protobuf是由字段索引(fieldIndex)与数据类型(type)计算(fieldIndex<<3|type)得出的key维护字段之间的映射且只占一个字节,所以相比json与xml文件,protobuf的序列化字节没有过多的key与描述符信息,所以占用空间要小很多。
七、Protobuf的源码分析
1、protobuf在java使用的序列化流程
java程序调用parserFrom(byte[] data)开始字节序列的反序列,Java程序通过调用编译生类GenerateMessage中的wirteTo()方法开始将序列化后的字节写入输出流中
GenerateMessage 继承AbstractMessage类,序列化最终在AbstractMesssage中完成,序列化的实现过程:
a、遍历对象中Message结构()
调用AbstractMessage类中的writeTo()方法
b、 序列化Message中每一个字段
调用CodeOutputStream类中的writeMessageSetExtension()方法
c、 对于Varints Tag 的序列化流程:
调用CodeOutputStream类中的writeUInt32()方法
调用CodeOutputStream类中的WriteRawVarint32()方法
d、 对于非Varints Tag的序列化
调用CodeOutputStream类中的WriteTag()方法
具体的序列化实现都在CodedOutputStream中完成
2、java使用protobuf 的反序列化流程分析
java程序通过调用parserFrom(byte[] data)开始反序列化
具体在com.google.protobuf. AbstractParser类中实现
最后在com.google.protobuf.CodedInputStream类中完成反序列化
3、动态编译
以windows下用protoc.exe工具实现proto文件编译为例,protoc.exe是用C++实现。在控制台执行命令:
编译的流程:
检查proto的语法规则
将proto的文件中的message结构转换为GenerateMessage类的子类,并实现Builder接口。
编译流程
Main.cc中的main()方法
Command_line_interface.cc中的Run()方法
Import类中Import()
在Descriptor中完成message消息的收集和转化。
相关推荐
- 悠悠万事,吃饭为大(悠悠万事吃饭为大,什么意思)
-
新媒体编辑:杜岷赵蕾初审:程秀娟审核:汤小俊审签:周星...
- 高铁扒门事件升级版!婚宴上‘冲喜’老人团:我们抢的是社会资源
-
凌晨两点改方案时,突然收到婚庆团队发来的视频——胶东某酒店宴会厅,三个穿大红棉袄的中年妇女跟敢死队似的往前冲,眼瞅着就要扑到新娘的高额钻石项链上。要不是门口小伙及时阻拦,这婚礼造型团队熬了三个月的方案...
- 微服务架构实战:商家管理后台与sso设计,SSO客户端设计
-
SSO客户端设计下面通过模块merchant-security对SSO客户端安全认证部分的实现进行封装,以便各个接入SSO的客户端应用进行引用。安全认证的项目管理配置SSO客户端安全认证的项目管理使...
- 还在为 Spring Boot 配置类加载机制困惑?一文为你彻底解惑
-
在当今微服务架构盛行、项目复杂度不断攀升的开发环境下,SpringBoot作为Java后端开发的主流框架,无疑是我们手中的得力武器。然而,当我们在享受其自动配置带来的便捷时,是否曾被配置类加载...
- Seata源码—6.Seata AT模式的数据源代理二
-
大纲1.Seata的Resource资源接口源码2.Seata数据源连接池代理的实现源码3.Client向Server发起注册RM的源码4.Client向Server注册RM时的交互源码5.数据源连接...
- 30分钟了解K8S(30分钟了解微积分)
-
微服务演进方向o面向分布式设计(Distribution):容器、微服务、API驱动的开发;o面向配置设计(Configuration):一个镜像,多个环境配置;o面向韧性设计(Resista...
- SpringBoot条件化配置(@Conditional)全面解析与实战指南
-
一、条件化配置基础概念1.1什么是条件化配置条件化配置是Spring框架提供的一种基于特定条件来决定是否注册Bean或加载配置的机制。在SpringBoot中,这一机制通过@Conditional...
- 一招解决所有依赖冲突(克服依赖)
-
背景介绍最近遇到了这样一个问题,我们有一个jar包common-tool,作为基础工具包,被各个项目在引用。突然某一天发现日志很多报错。一看是NoSuchMethodError,意思是Dis...
- 你读过Mybatis的源码?说说它用到了几种设计模式
-
学习设计模式时,很多人都有类似的困扰——明明概念背得滚瓜烂熟,一到写代码就完全想不起来怎么用。就像学了一堆游泳技巧,却从没下过水实践,很难真正掌握。其实理解一个知识点,就像看立体模型,单角度观察总...
- golang对接阿里云私有Bucket上传图片、授权访问图片
-
1、为什么要设置私有bucket公共读写:互联网上任何用户都可以对该Bucket内的文件进行访问,并且向该Bucket写入数据。这有可能造成您数据的外泄以及费用激增,若被人恶意写入违法信息还可...
- spring中的资源的加载(spring加载原理)
-
最近在网上看到有人问@ContextConfiguration("classpath:/bean.xml")中除了classpath这种还有其他的写法么,看他的意思是想从本地文件...
- Android资源使用(android资源文件)
-
Android资源管理机制在Android的开发中,需要使用到各式各样的资源,这些资源往往是一些静态资源,比如位图,颜色,布局定义,用户界面使用到的字符串,动画等。这些资源统统放在项目的res/独立子...
- 如何深度理解mybatis?(如何深度理解康乐服务质量管理的5个维度)
-
深度自定义mybatis回顾mybatis的操作的核心步骤编写核心类SqlSessionFacotryBuild进行解析配置文件深度分析解析SqlSessionFacotryBuild干的核心工作编写...
- @Autowired与@Resource原理知识点详解
-
springIOCAOP的不多做赘述了,说下IOC:SpringIOC解决的是对象管理和对象依赖的问题,IOC容器可以理解为一个对象工厂,我们都把该对象交给工厂,工厂管理这些对象的创建以及依赖关系...
- java的redis连接工具篇(java redis client)
-
在Java里,有不少用于连接Redis的工具,下面为你介绍一些主流的工具及其特点:JedisJedis是Redis官方推荐的Java连接工具,它提供了全面的Redis命令支持,且...
- 一周热门
- 最近发表
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- resize函数 (64)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- mybatis大于等于 (64)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- linuxlink (65)
- pythonwget (67)
- androidinclude (65)
- logstashinput (65)
- hadoop端口 (65)
- vue阻止冒泡 (67)
- oracle时间戳转换日期 (64)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)