删除或更新信息,请邮件至freekaoyan#163.com(#换成@)

一种Protobuf到JSON动态转换方法

本站小编 Free考研考试/2022-01-02

田丹,1, 张金杰,2,3,*, 李翀,2,3, 曲艳华4, 焦昊41.中国中钢集团有限公司,北京 100180
2.中国科学院计算机网络信息中心,北京 100190
3.中国科学院大学,北京 100049
4.战略支援部队航天系统部,北京 100094

A Dynamic Conversion Method from Protobuf to JSON

Tian Dan,1, Zhang Jinjie,2,3,*, Li Chong,2,3, Qu Yanhua4, Jiao Hao41. Sinosteel Group Corporation Limited, Beijing 100180, China
2. Computer Network Information Center, Chinese Academy of Sciences, Beijing 100190, China
3. University of Chinese Academy of Sciences, Beijing 100049, China
4. Strategic Support Force Space Systems Division, Beijing 100094, China

通讯作者: 张金杰(E-mail:zhangjinjie1996@163.com

收稿日期:2020-07-6网络出版日期:2020-08-20

Received:2020-07-6Online:2020-08-20
作者简介 About authors

田丹,中国中钢集团公司,资深信息化主管,主要工作内容为企业信息化,有丰富的信息化规划建设经验,研究领域为Web技术和数据挖掘、数据融合。
本文主要承担总体设计、技术调研及相关部分撰写。
Tian Dan is a senior Information Supervisor of Sinosteel Corporation. She is interested in the research fields of web technology, data mining, and data fusion.
In this paper, she is mainly responsible for the overall approach design and technical investigation.
E-mail: 45443620@qq.com


张金杰,中国科学院计算机网络信息中心,硕士研究生,主要研究方向为管理大数据、推荐技术、高级软件体系结构等。
本文主要承担工作为算法实现。
Zhang Jinjie is a master student at Computer Network Information Center, Chinese Academy of Sciences. His main research interests are big data management, recommendation technology, advanced software architecture, etc.
In this paper, he is mainly responsible for the realization of the algorithms.
E-mail: zhangjinjie1996@163.com


李翀,中国科学院计算机网络信息中心,高级工程师,中国计算机学会高级会员,主要研究方向为管理大数据、推荐技术、高级软件体系结构等。以第一作者及通讯作者发表论文20余篇。
本文主要承担工作为实验分析。
Li Chong is a senior engineer at the Computer Network Information Center, Chinese Academy of Sciences. He is also a senior member of the Chinese computer society. His main research interests include big data management, recommendation technology, and advanced software architecture.
In this paper, he is mainly responsible for the experimental analysis.
E-mail: lichong@cnic.cn





摘要
【背景】Protobuf和JSON是目前两种主流网络数据结构,有着各自的特点和应用场景,随着互联网应用的场景复杂,不同场景下数据交换上有了新的要求。JSON主要应用于Web浏览器到服务器数据传输,Protobuf主要用于客户端到服务器端高效安全数据传输。【目的】若能实现两者的转换,可以促进数据交互,极大地提高开发效率。【方法】本文基于动态解析和类型反射技术,实现了Protobuf和JSON数据动态转换,并搭建测试平台和编写测试用例进行了验证。【结果】实验表明,该方法可靠稳定兼容性好,在测试用例不同测试数据下转换效率保持20MB/s,Protobuf 2和Protobuf 3均可正常转换。
关键词: Protobuf;JSON;转换;动态解析;类型反射

Abstract
[Background] Two mainstream network data structures, Protobuf and JSON, have their own characteristics and application scenarios. With the growing complexity of network applications, data exchanges under different scenarios are required. In traditional, JSON is mainly used for data transmission from the Web browser to the server, while Protobuf is mainly for efficient and safe data transmission from clients to servers. [Objective] Thus, if the data format of JSON and Protobuf exchange can be achieved, it will promote data interactions and greatly improve development efficiency. [Methods] This article implements the dynamic data conversion method to convert Protobuf data to JSON format based on dynamic parsing and type reflection technologies. Besides, a test platform with multiple test cases for verifications has been built. [Results] Experiments show the proposed method is reliable and stable with good compatibility. The conversion capacity maintains at 20MB/s under different test data of the test cases for both Protobuf 2 and Protobuf 3.
Keywords:Protobuf;JSON;conversion;dynamic analysis;type reflection


PDF (6939KB)元数据多维度评价相关文章导出EndNote|Ris|Bibtex收藏本文
本文引用格式
田丹, 张金杰, 李翀, 曲艳华, 焦昊. 一种Protobuf到JSON动态转换方法. 数据与计算发展前沿[J], 2020, 2(4): 155-164 doi:10.11871/jfdc.issn.2096-742X.2020.04.013
Tian Dan, Zhang Jinjie, Li Chong, Qu Yanhua, Jiao Hao. A Dynamic Conversion Method from Protobuf to JSON. Frontiers of Data and Computing[J], 2020, 2(4): 155-164 doi:10.11871/jfdc.issn.2096-742X.2020.04.013


开放科学标识码(OSID)

引言

随着互联网的不断发展,兴起了多种数据交换格式,其中比较常用的便是JSON、Google Protocol Buffer和XML,他们都有各自的使用场景。JSON是一种轻量级的数据交换格式,它基于JavaScript的一个子集,采用完全独立于语言的文本格式,易于编写和解析[1]。Google Protocol Buffer(简称Protobuf或PB)是一种灵活高效的、用于序列化结构化数据的机制,类似于XML,但比XML更小且更简单[2]。Protobuf序列化为二进制数据,不依赖平台和语言,同时具备很好的兼容性。XML是一种重量级数据交换格式,是可扩展标记语言。相比于前两种数据交换格式,XML占用带宽比较大,现在主要用于描述数据和用作配置文件,在服务器与Web/客户端中使用较少[3]。本文重点研究JSON和Protobuf的互相转换方法。

JSON和Protobuf都是应用非常广泛的数据交换格式,两者在使用场景上有所不同:JSON主要用于Web场景、数据对人可读、服务端应用程序向Web浏览器发送数据和跨组织的API的交互场合更适合;Protobuf自带加密功能,主要用于客户端到服务器端高效安全数据传输。Protobuf编解码速度和数据大小上有更多优势,可以得到最快的序列化速度和最小的结果[4]。当Protobuf数据需要发送给Web浏览器以供人们浏览时,或者Web浏览器产生的JSON数据需要大批量进行高效传输时,需要两种异构数据进行相互转换。

目前开源的JSON与Protobuf的转换工具有Flask-Pbj、pbf2JSON、Node-proto2JSON、pb2doc等。Flask-Pbj是基于python实现的,它提供了对Protobuf和JSON格式的请求和响应数据的支持,且API修饰器可以实现JSON或Protobuf格式的消息与Python字典之间的序列化和反序列化。pbf2JSON是基于Go实现的,它是一个输出JSON的OpenStreetMap pbf解析器,允许用户挑选标签并处理反规范化的方式和关系,可作为独立的二进制文件提供,并带有方便的npm包装器。Node-proto2JSON是基于JavaScript的 .proto文件到JSON 转换器,没有额外的依赖关系。pb2doc是用于将Protobuf消息转换为JSON或html的解析器,具有递归解析消息、支持grpc服务、可配置的文档类型、基于注释的服务描述等功能。可见,上述转换工具开发语言各异且较小众,多数工具使用步骤繁琐复杂,只能实现单向转换,或者无法实现批量转换。

本文基于C语言实现了Protobuf与JSON数据转换,可以方便快捷地将Protobuf格式的二进制数据批量转换为JSON格式的文本数据,该方法可靠稳定且兼容性好,同理也很容易将若干JSON数据批量转换为Protobuf格式二进制数据。

1 相关技术

1.1 Protocol Buffer

Protobuf是Google公司内部的混合语言数据标准,最新版本为3.X,最初用于实现客户端与服务器之间的通信协议,是一种灵活高效的结构化数据存储格式[5]。Google提供了一套软件库,可以把Protobuf的记录序列化和反序列化,序列化后的数据小以及数据解析速度快,方便网络传输和存储。由于Protobuf是二进制数据格式,编码和解码双方必须有共同的.proto文件才能获取到相应的信息,数据本身不具有可读性,因此只能反序列化之后得到真正可读的数据,一定程度上保证了其安全性;另一方面,二进制数据比使用XML等其他类型进行数据交换要快得多,因此可以把它用于分布式应用之间的数据通信或者异构环境下的数据交换[6,7]。作为一种效率和兼容性都很优秀的二进制数据传输格式,Protobuf可以用于诸如网络传输、配置文件、数据存储等诸多领域,目前提供了 C++、Java、Python、JS、Ruby等多种语言的API。

要使用Protobuf,首先我们需要编写一个.proto文件来定义结构化数据Message。如图1所示,Protobuf还允许对消息的嵌套,使得其能够表达更为复杂的数据结构,功能更加强大。

图1

新窗口打开|下载原图ZIP|生成PPT
图1消息的嵌套

Fig.1Demo for nested message types



通过Protobuf编译器将.proto文件转换成对应平台(Python、C++、Java)的代码文件。在C/C++中通过包含该代码的头文件就能使用定义好的数据类型,诸如对消息的成员进行赋值,将消息序列化等都有相应的方法。

1.2 序列化和反序列化

Protobuf的核心技术之一是序列化与反序列化。序列化是指将数据结构或对象转换成二进制串的过程,而反序列化则是上述过程的逆操作,即将序列化过程中所生成的二进制串转换成数据结构或者对象。

Protobuf将消息里的每个字段进行编码后,再利用T-L-V存储方式进行数据的存储,最终得到的是一个二进制字节流[8]。其中T即Tag,字段的标识号,也叫Key;L是Value的字节长度;V是该字段对应的值Value,即消息字段经过编码后的值。序列化后的Value是按原样保存到字符串或者文件中,Key按照一定的转换条件保存起来,序列化后的结果就是如图2所示的形式。

图2

新窗口打开|下载原图ZIP|生成PPT
图2序列化结果T-L-V示意

Fig.2Serialization result T-L-V diagram



Key的序列化格式是按照Message中字段后面的域号与字段类型来转换。序列化过程不需要分隔符就能分隔字段,各个字段存储得非常紧凑,存储空间利用率非常高;如果一个字段没有被设置字段值,那么该字段在序列化时对应的数据中是完全不存在的,即不需要编码。同时序列化涉及到的运算也仅是一些简单的数学操作,只用到Protocol Buffer 自身的框架代码和编译器,无需其他的工具,这些特点共同保证了运算的高效。

Protobuf反序列化过程如下:(1)调用消息类的parseFrom(input) 解析从输入流读入的二进制字节数据流;(2)将解析出来的数据按照指定的格式读取到Java、C++、Python对应的结构类型中。由于反序列化是序列化的逆过程,因此同样无需复杂的词法语法分析,解析过程只需要通过简单的解码方式即可完成[9]

1.3 Jansson开源库

Jansson[10]是一个用于解码、编码和操作JSON的C语言库,其提供了简单直观的API和数据模型,无需其他依赖项,并完整地支持Unicode编码。JSON规范定义了以下数据类型:对象、数组、字符串、数字、布尔值和Null。Jansson库中分别对应JSON_OBJECT、JSON_ARRAY、JSON_STRING、JSON_INTEGER、JSON_REAL、JSON_TRUE、JSON_FALSE、JSON_NULL类型。由于JSON数据结构是动态变化的,使用数据结构JSON_t来表示所有JSON值。JSON_typeof函数可以获得JSON值的类型。

Jansson库中所有以JSON值作为参数的函数都将管理引用,即根据需要增加和减少引用计数。创建新JSON值的函数将引用计数设置为1。如果函数调用增加了引用计数,一旦不再需要该值,应调用JSON_decref释放引用,即该值将被销毁并且无法再使用。

2 设计与实现

在本部分,本文以Protobuf转JSON为例,详细地介绍设计思路与具体的实现方法。而JSON转Protobuf为其的逆过程,两者使用的思路与方法基本一致,且从JSON结构化到二进制转换相对更简单,本文不再赘述。

2.1 设计思路

将Protobuf转换为JSON,需要以下四个步骤:

(1)读入二进制文件和.proto描述文件;

(2)根据.proto文件解析出消息类型结构;

(3)动态解析出二进制文件中每条数据所属的消息类型及其各个字段的含义,并组成一个或多个消息对象;

(4)根据消息对象中的每个field的类型和属性,找到其对应的JSON格式,构造为JSON数据。

综合以上四个步骤,本文将实现的主要内容分为两个模块:二进制文件的动态解析模块和Protobuf转JSON模块。

2.2 动态解析方法

2.2.1 问题分析

通常输入仅有Protobuf的Schema定义以及相应的二进制Protobuf数据,即Message的定义事先是未知的,因此我们需要根据.proto文件解析出每条Message的结构,根据Protobuf二进制数据解析出不同的数据记录,并确定每条数据记录所对应的消息类型。

由于Protobuf打包的数据没有自带长度信息或终结符,当有多条序列化二进制数据时,我们无法判断哪一部分对应的是一条完整的数据,无法直接进行反序列化。因此需要解决如下问题:第一:长度。由应用程序自己在发送和接收的时候做正确的切分;要求生成的分隔符不能与消息内容重复,否则可能出现无法区分的情况,从而无法获取正确的Protobuf格式的数据。第二:类型。Protobuf打包的数据没有自带类型信息,需要由发送方把类型信息发送给接收方,接收方创建具体的 Protobuf Message 对象,再做对应的反序列化。

因此我们规定分隔符形式为:^@UCAS@Message_type^,其中Message_type表示每条完整的二进制数据对应的类型。将其添加分隔符后如图3所示。

图3

新窗口打开|下载原图ZIP|生成PPT
图3加入分隔符后的序列化二进制数据

Fig.3Serialized binary data with delimiters



根据对应的分隔符,可以明确得出图中含有三条序列化二进制数据,第一条、第三条对应的消息类型为Person,第二条对应的消息类型为Test。

在确定了每条数据的内容以及其所对应的Message类型后,接下来需要研究如何自动创建具体的 Protobuf Message 对象,再对其做相应的反序列化。Google Protobuf 本身实现了根据 type name 创建具体类型的 Message 对象这一功能。Protobuf Message class 采用了 prototype pattern,Message class 定义了 New() 虚函数,用以返回本对象的一份新实例,类型与本对象的真实类型相同。也就是说,只需要Message* 指针,而不用知道它的具体类型,就能创建和它类型一样的具体 Message Type 的对象。具体的实现步骤如下:

(1)调用 DescriptorPool::generated_pool() 找到一个 DescriptorPool 对象,它包含了程序编译的时候所链接的全部 Protobuf Message types。

(2)调用DescriptorPool::FindMessageTypeByName() 根据 type name 查找相应 Descriptor。

(3)调用 MessageFactory::generated_factory()找到 MessageFactory 对象,创建程序编译的时候所链接的全部 Protobuf Message types。

(4)调用 MessageFactory::GetPrototype() 找到具体 Message Type的default instance。

(5)调用 prototype->New() 创建对象。

2.2.2 主要代码实现

(1)string analyPackage(string protoPath)

函数参数:.proto文件的路径。

函数功能:根据.proto文件解析出对应的包名,若没有则返回空。如果.proto文件中使用了package语句,则需要使用对应的package_name才能访问其内部的Message类型。

(2)string analyMessage(string protoPath);

函数参数:.proto文件的路径。

函数功能:保证程序的健壮性。我们要求序列化的文件一定要有分隔符,若没有检测到分隔符,则默认该条数据对应.proto文件的第一个Message类型,此时需要从.proto文件解析其第一条Message类型。

(3)string regexClassName(string p_str)

函数参数:给定的字符串(含有自定义的分隔符)。

函数功能:从分隔符中获取二进制数据所对应的类型。采取正则表达式的方式来实现:

regex reg(“\\^@UCAS@(.*)\\^”)

smatch m;

auto ret = regex_search(p_str, m, reg);

(4)int dynamicParseFromProtoFile(const string &filePath, const string &MessageName, function<void(::google::protobuf::Message *msg)> callBack)

函数参数:.proto文件的路径;.proto文件中第一个Message类型;回调函数。

函数功能及说明:对给定的一条二进制数据msg进行动态解析,若某条二进制数据不含有分隔符,则默认其对应.proto文件的第一个Message类型。回调函数就是一个通过函数指针调用的函数。本函数的第三个参数为一个回调函数,该函数的参数为一个::google::protobuf::Message类型的指针,用于承接解析出来的Protobuf数据。

动态解析部分的核心代码如下:

// 进行文件系统的配置

::google::protobuf::compiler::DiskSourceTree sourceTree;

// 将当前路径映射为项目根目录

sourceTree.MapPath(“”, path);

// 进行动态编译器的配置

::google::protobuf::compiler::Importer importer (&sourceTree, NULL);

// 动态编译proto源文件

importer.Import(fileName);

// 从编译器中提取具体Message类型的描述信息.

const ::google::protobuf::Descriptor *descriptor =importer.pool()->FindMessageTypeByName(MessageName);

// 创建一个动态的消息工厂

::google::protobuf::DynamicMessageFactory factory;

// 从消息工厂中创建出一个类型原型.

const ::google::protobuf::Message *Message = factory.GetPrototype(descriptor);

// 构造一个可用的消息.

::google::protobuf::Message *msg = Message->New();

// 通过反射接口来对字段进行赋值等相关操作

2.3 转换方法

2.3.1 问题分析

得到Protobuf格式的消息对象后,需要对消息对象中的数据进行解析,并按照JSON格式构建数据,转换为字符串类型,写入JSON文件。

需要用到Protobuf提供的Descriptor、Field-Descriptor和Reflection类的API。

Descriptor类:描述一种Message类型(不是一个单独的Message对象)的meta信息。可以通过Descriptor获取任意Message或service的属性和方法,包括Message的名字、所有字段的描述、原始的proto文件内容。

FieldDescriptor类:Message中的每项field类型的描述类,利用该类就能获得每个field的名称、类型、属性等信息。

Reflection类:提供方法来动态访问/修改Message中的field的接口类,遍历解析其中的每个field获取对应的值。

解析每个filed的过程是:首先需要判断field的属性是否为重复的(repeated),如果是重复的,则需要获取其重复数量和数据类型,依次读取每一项进行转换。重复的field对应于JSON中的数组类型,其每一项都转换为数组的一个元素。如果不是重复的,则需要判断是否为可选的(optional)。如果是可选的,则判断这个field是否设值,有值则进行以下判断:

(1) 如果是布尔、字符串和数值类型,则转换为一个JSON对象的键值对,key为field的名字,由field->name()得到,value为该field的值。其中Double、Float类型对应JSON中实数类型,Int32、Int64、UInt32、UInt64类型对应JSON中的整数类型。

(2) 如果是枚举类型,同样转换为一个JSON对象的键值对。可以通过getEnum->name()获得字符串,或者getEnum->number()获取其索引值,可以选取任意一项作为value。

(3) 如果是Message类型,同样对应为一个JSON对象,其内部的子消息,对应嵌套的JSON对象。key是field的名字,value则是子JSON对象,通过递归调用解析函数进行嵌套填充。

需要注意的是,由于Jansson库不支持二进制字节的字符,当字符串是二进制字节表示时,即类型为FieldDescriptor::TYPE_BYTES,需要转换为十六进制序列。需要遍历所有字节,进行与运算,转为十六进制字符,然后拼接成字符串。使用JSON_dumps函数将构造好的JSON对象转换为字符串,并通过ofstream流将字符串输出到文件中。

2.3.2 主要代码实现

(1)char *pb2JSON(Message *msg, char *buffer)

函数参数:空消息对象msg,二进制数据缓冲区buffer

函数功能:适用于实参是二进制数据buffer,在函数里先进行反序列化成Protobuf数据,保存在提供的空Message对象中,然后再进行转换。返回值是JSON的字符串形式。

(2)char *pb2JSON(Message *msg)

函数参数:消息对象msg

函数功能:适用于实参是解析好的Protobuf数据,直接对msg的内容进行转换;其内部功能由以下函数实现:

①JSON_t *parseFromMsg(const Message *msg)

函数参数:消息对象msg

函数功能:对msg的每个field进行判断和处理,生成对应的JSON对象作为返回值。

②JSON_t *parseFromRepeatField(const Message *msg, const FieldDescriptor *field)

函数参数:消息对象msg,field的描述类对象

函数功能:对判断为重复属性的field进行解析,利用for循环对所有项进行处理,返回一个JSON对象。

③string hexEncode(string binInput)

函数参数:二进制的字符串binInput

函数功能:将每个二进制字符转为十六进制字符,然后拼接成字符串,返回十六进制字符串。

3 实验验证

3.1 环境配置

实验环境为Ubuntu 20.04 LTS,Protobuf 3.11.4,Jansson 2.12,GCC 9.3.0。

首先需要编译安装Protobuf与Jansson库,因为本文是基于C平台的转换工具,因此需要GCC环境,安装配置过程本文不再赘述。

然后通过Protobuf编译器编译.proto文件,生成.h文件和.cc文件。通过在C/C++代码中包含.h头文件,可以使用其中的一系列获取、设置字段值等方法为Message中的字段赋值,编写测试用例。

3.2 正确性测试

为了验证转换的正确性,本文针对三种比较极端的场景进行测试:

(1)定义一条Message,Message含有很多成员;

(2)定义多条Message,每条Message不含或仅含较少成员;

(3)多重嵌套测试。

进行正确性测试的目的是测试程序能否正常执行,以及当传递以上3种情况的信息时,程序能否对每个Message以及Message内部的成员进行正确的解析并返回正确结果。

多重嵌套用例如图4所示,实验表明设置大量Message Type对象并不影响程序的正确性,解析程序可以正确转换多重嵌套的Message情况。且由于每个Message中的成员较少,Message在处理能力范围内对性能的影响不大,可以保证较好的运行效率。测试结果如图5所示。

图4

新窗口打开|下载原图ZIP|生成PPT
图4多层嵌套用例

Fig.4Multilevel nested message use case



图5

新窗口打开|下载原图ZIP|生成PPT
图5多层嵌套测试结果

Fig.5Conversion result of multilevel nested message



综合分析正确性测试,可以得出结论,我们的解析程序可以对每个Message以及Message内部的成员进行正确的解析,且具有较好的稳定性,能够适用于绝大多数的信息转换情形。而且通过测试可以得知,当不同Message定义有几乎相同的数据结构时,解析时可以相互套用不影响正确性。但是针对多重嵌套,要注意其正确的嵌套格式。

3.3 性能测试

测试解析程序在一次性解析大量数据时的承受能力以及Protobuf转JSON的性能。

经过查阅官方文档得知,Protobuf对于定义的信息文件有默认大小的限制,要解析的数据不能超过默认的64MB,否则会解析失败。

首先测试单次Protobuf可以转换多大量的JSON数据。该部分测试,我们采用fixed32类型作为多次重复传递的消息,因为fixed32类型在Protobuf的定义中为固定的4bytes大小,方便我们计算一次传输的数据量。

3.3.1 对单条Message解析测试

利用循环添加1000、10 000、100 000个fixed32类型数据,每个为4bytes大小,都由repeated来修饰,定义的字段可出现0到多次。数据均成功解析。100 000条数据均成功解析成JSON格式如图6所示。

图6

新窗口打开|下载原图ZIP|生成PPT
图6100 000个fixed32类型数据执行结果

Fig.6Conversion results for single message with 100 000 fixed32 data



3.3.2 对多条Message解析测试

同理,利用循环对单次转换多条Message进行了测试,Message中包含由optional修饰的字段数据“123”。 用同样方式测试1000、10 000、100 000条该定义下的Message,编译执行后,均能成功解析。100 000条Message的执行结果如图7所示,可以看到所有Message均成功转换为对应的JSON格式。

图7

新窗口打开|下载原图ZIP|生成PPT
图7100000条Message执行结果

Fig.7Conversion Results for 100 000 Messages



3.3.3 转换性能测试

我们在生成测试数据的C++文件中定义了一条拥有N个成员信息的Message和N个空的Message,通过控制N的大小来不断增大数据量。通过在多次测试,得出在Mac电脑(测试机型配置:i5-8279U,16GB LPDDR3,M.2固态硬盘)上的平均运行性能,如表1所示。

Table 1
表1
表1有空Message 时测试结果
Table 1Testing results with null message
文件大小(Bytes)23,124230,125511,2311,150,1252,300,125
解析时间(s)2.26933.62387.119187.182435.625
性能(B/s)10,191.276,844.275,868.196,144.425,280.06

新窗口打开|下载CSV

我们认为解析N个空的Message可能会影响解析速度,因为大量的Message就意味着需要解析大量的分隔符,而分隔符的定义对于解析批量的Protobuf数据是不可避免的,所以我们剔除对N个空的Message的解析,单纯测试解析一条拥有N个成员信息的Message的性能,如表2所示。

Table 2
表2
表2排除空Message后的测试结果
Table 2Testing results without null message
文件大小(Bytes)200,125400,1251,000,1252,320,126
解析时间(ms)11.30119.45452.871101.833
性能(MB/s)16.8819.6118.0421.72

新窗口打开|下载CSV

可以看出,解析一条拥有N个成员信息的Message的性能已基本保持线性,可以达到20 MB/s左右,这证明我们解析程序有着很好的纯转换性能。综上可以认为该Protobuf转换JSON程序有良好的解析性能,但是信息传输应该尽量使用少次大数据量的Message来代替使用多次小数据量的Message,从而提升转化效率。

3.4 兼容性测试

上述所有测试都是在Protobuf 2版本下进行的,本部分测试内容将Protobuf替换为3.X版本进行测试。Protobuf 3移除了“required”类型的字段,因为 required 字段通常被认为是有害的且违反了 Protobuf 的兼容性语义,并用“singular”来替代原本的“optional”。字段的默认值只能根据字段类型由系统决定,而不能使用 default 选项为某一字段指定默认值,对于枚举类型,默认值必须为0。

针对proto3的特性重新进行测试,程序能够正确地完成Protobuf到JSON的转换。所以,本文提出的转换方法同样适用于Protobuf 3版本,支持转换Protobuf 3所提供的所有数据类型,具有很好的兼容性。

4 结论展望

本文基于动态解析技术与类型反射技术,实现了一种便捷的Protobuf与JSON转换的方法。经过测试,该方法稳定性好、兼容性佳、性能稳定,可以胜任实际生产需要。需要指出得是,本文的各项测试仅在单线程下,若开启多个线程同时进行转换,转换效率将会进一步提高。

本文的实现存在一定的局限性, 如Protobuf间隔符有极小概率会与消息内容产生冲突且对转换效率有一定影响,在接下来的工作中可以设计使用具有固定字长的分隔符,能在一定程度上解决上述问题。

利益冲突声明

所有作者声明不存在利益冲突关系。

参考文献 原文顺序
文献年度倒序
文中引用次数倒序
被引期刊影响因子

Lv T, Yan P, He W . Survey on JSON Data Modelling
[J]. Journal of Physics Conference, 2018: 1069.

[本文引用: 1]

LU Z, GUO Z . The Principle and Application of Protocol Buffer
[J]. Science & Technology Vision, 2015 ( 19):45-146.

[本文引用: 1]

Gligori? N, Dejanovi? I, Kr?o S . Performance evaluation of compact binary XML representation for constrained devices
[C]//2011 international conference on distributed computing in sensor systems and workshops (DCOSS). IEEE, 2011: 1-5.

[本文引用: 1]

Popi? S, Pezer D, Mrazovac B , et al. Performance evaluation of using Protocol Buffers in the Internet of Things communication
[C]//2016 International Conference on Smart Systems and Technologies (SST). IEEE, 2016: 261-265.

[本文引用: 1]

聂晓旭, 于凤芹, 钦道理 . 基于Protobuf的数据传输协议
[J]. 计算机系统应用, 2015,24(08):112-116.

[本文引用: 1]

Kaur G, Fuad M M . An evaluation of protocol buffer
[C]//Proceedings of the IEEE SoutheastCon 2010 (SoutheastCon). IEEE, 2010: 459-462.

[本文引用: 1]

Wendt A, Faschang M, Leber T , et al. Software architecture for a smart grids test facility
[C]//IECON 2013-39th Annual Conference of the IEEE Industrial Electronics Society. IEEE, 2013: 7062-7067.

[本文引用: 1]

黄斌, 谢艳新, 唐友 . 数据存储信息序列化完整性及效率评估仿真
[J]. 计算机仿真, 2020,37(4):159-163.

[本文引用: 1]

Ayham H M, Nikolaev A B . Data Transmission over the Network Using PROTOBUF Protocol
[J]. 2015: 3.

[本文引用: 1]

JanssonDocumentation
[EB/OL]. [2020-05-07]. https://jansson.readthedocs.io/en/2.13/.

URL [本文引用: 1]

相关话题/数据 测试 信息 程序 过程