xml,json,protobuf

XML、JSON和protobuf都是常见的数据传输格式,各有优缺点。XML可读性好但性能较低,适合OpenAPI;JSON普及广泛,性能优于XML;protobuf则在高性能、小数据量传输中表现出色,适合高负载应用。数据传输时需注意半包问题,解决方法是在应用层进行数据包重组。protobuf通过.proto文件定义消息类型,支持required、optional和repeated字段规则,提供高效编码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

xml,json,protobuf简介

XML,json,protobuf都可以用来存储和传输结构化数据。
在开发一些涉及远程过程调用(RPC)的程序时,需要对传输的对象进行序列化和反序列化。序列化过程需要对传输的结构化数据进行编码和格式化(Encoding & Format),常用的编码类型有:

  1. XML:数据在序列化成字节流之前都转换成字符串。可读性良好,性能差,Open API类型的应用中常用。所谓的OpenAPI是服务型网站常见的一种应用,网站的服务商将自己的网站服务封装成一系列API(Application Programming Interface,应用编程接口)开放出去,供第三方开发者使用,这种行为就叫做开放网站的API,所开放的API就被称作OpenAPI。
  2. JSON:最常用的编码方式,可读性较强但性能稍差。JSON的普及性是由于其在数据交换格式方面显然具有很大的优势,例如:用户群庞大,可阅读性强,可以通过网络轻松共享,数据可以是任何类型(嵌套元素、数组等)。但它也有一些缺点:架构未强制执行,由于重复的键,对象可能很大,不支持评论、元数据或文档。
  3. Protobuf:Protobuf是Google提出的一种数据交换的格式,是一套类似JSON或者XML的数据传输格式和规范,用于不同应用或进程之间进行通信。Protobuf的编码过程为:使用预先定义的Message数据结构将实际的传输数据进行打包,然后编码成二进制的码流进行传输或者存储。Protobuf的解码过程则刚好与编码过程相反:将二进制码流解码成Protobuf自己定义的Message结构的POJO实例。相对于文本格式的数据交换(JSON、XML)来说,Protobuf更加适合于高性能、快速响应的数据传输应用场景。对于打造一款高性能的通信服务器来说,Protobuf传输协议是最高性能的传输协议之一。微信的消息传输就采用了Protobuf协议。
  4. 其他开源的序列化/反序列化框架,例如Apache Avro, Apache Thrift,这两个框架和Protobuf相比,性能非常接近,而且设计原理如出一辙;其中Avro在大数据存储(RPC数据交换,本地存储)时比较常用;Thrift的亮点在于内置了RPC机制,所以在开发一些RPC交互式应用时,客户端和服务器端的开发与部署都非常简单。
    在这里插入图片描述

数据传输中的半包问题

评价一个序列化框架的优缺点,大概从两个方面着手:
(1)结果数据大小,原则上说,序列化后的数据尺寸越小,传输效率越高。
(2)结构复杂度,这会影响序列化/反序列化的效率,结构越复杂,越耗时。
无论是使用JSON和Protobuf,还是其他的反序列化协议,我们必须保证在数据包的反序列化之前,接收端的ByteBuf二进制包一定是一个完整的应用层二进制包,不能是一个半包或者粘包。因此理论上来说,对于对性能要求不是太高的服务器程序,可以选择JSON系列的序列化框架;对于性能要求比较高的服务器程序,则应该选择传输效率更高的二进制序列化框架,目前的建议是Protobuf。
半包现象的形成是由于底层网络是以二进制字节报文的形式来传输数据的。首先,每次读取底层缓冲的数据容量是有限制的,当TCP底层缓冲的数据包比较大时,会将一个底层包分成多次ByteBuf进行复制,进而造成进程缓冲区读到的是半包。当TCP底层缓冲的数据包比较小时,一次复制的却不止一个内核缓冲区包,进而造成进程缓冲区读到的是粘包。解决的基本思路是,在接收端,根据自定义协议,将读取到的进程缓冲区ByteBuf,在应用层进行二次拼装,重新组装我们应用层的数据包。接收端的这个过程通常也称为分包,或者叫作拆包。

protobuf

1.编写protobuf文件时需要其特有的源文件,扩展名为 .proto,并在该源文件中定义存储类的内容。protobuf有自己的编译器protoc,可以将 .proto 编译成使之成为一个可以在 C++ 工程中直接使用的类。
2…proto文件中将一种结构称为一个message类型:

// FileName: tutorial.person.proto 
// 通常文件名建议命名格式为 包名.消息名.proto 
// 表示正在使用proto或proto32命令,若不指定则默认为proto2
syntax = "proto2"; 
 
//包声明,tutorial 也可以声明为二级类型。例如a.b,表示a类别下b子类别
package tutorial; 

message Car { 
  required string brand = 1;  
  required int32 VIN = 2;  
  optional float price = 3;  
  
 /*
 枚举类型的第一个常量映射到 0 :每个枚举的定义必须包含一个映射到 0 的常量作为第一个元素
 */
  enum carType {  
    A4 = 0;  
    A6 = 1;    
  } 
}
 

3.在proto2中:
包声明:proto 文件以package声明开头,这有助于防止不同项目之间命名冲突。在C++中,以package声明的文件内容生成的类将放在与包名匹配的namespace中,上面的.proto文件中所有的声明都属于tutorial。

字段规则:
required:消息体中必填字段,不设置会导致编解码异常。
optional: 消息体中可选字段,可通过default关键字设置默认值。
repeated: 消息体中可重复字段,重复的值的顺序会被保留。其中,proto3默认使用packed方式存储,这样编码方式比较节省内存。

标识号:在消息体的定义中,每个字段都必须要有一个唯一的标识号,标识号是[0,2^29-1]范围内的一个整数。

数据定义:许多标准的简单数据类型都可以用作message字段类型,包括bool,int32,float,double和string。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值