ProtocolBuffers(protobuf)详解

news2024/10/5 17:15:52

目录

    • 前言
    • 特点
    • 语法定义
    • 关键字
    • JSON与Protocol Buffers互相转换
    • gRPC与Protocol Buffers的关系

在这里插入图片描述

前言

Protocol Buffers(通常简称为protobuf)是Google公司开发的一种数据描述语言,它能够将结构化数据序列化,可用于数据存储、通信协议等方面。这种序列化格式很灵活、高效、自动化,不依赖于语言和平台并且可扩展性极强。使用protobuf时,您只需将数据结构定义一次(使用.proto文件定义),便可以使用特别生成的源代码轻松地使用不同的数据流完成对这些结构数据的读写操作,即使使用不同的语言(protobuf的跨语言支持特性)。您甚至可以更新数据结构的定义(就是更新.proto文件内容),而不会破坏依赖“老”格式编译出来的程序。

在这里插入图片描述

特点

Protocol Buffers主要具有以下三大特点:

  • 语言无关 :支持多种语言,包括但不限于Java、Python、C++、JavaScript、Go、Ruby、PHP、Objective-C、C#等。
  • 平台无关 :可生成不同语言的代码并在任何环境中运行。
  • 性能好、扩展性好 :序列化和反序列化性能相比 JSON 和 XML 等更快,平均每秒可以处理 10 万条消息。在微服务场景中,使用合适的序列化协议会大大提高系统的性能。

在这里插入图片描述

语法定义

Protocol Buffers(Protobuf)的语法主要包括以下几个部分:

  1. 消息定义:在 .proto 文件中定义消息,消息由字段组成。字段有三种类型:requiredoptionalrepeated,分别表示必须、可选和重复。
message Person {
  required string name = 1;
  optional int32 id = 2;
  repeated string email = 3;
}
  1. 枚举定义:枚举类型允许你定义一组有限的可能的值。
enum PhoneType {
  MOBILE = 0;
  HOME = 1;
  WORK = 2;
}
  1. 服务定义:服务允许你定义一组相互关联的RPC(远程过程调用)。
service HelloService {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}
  1. 字段编号:每个字段都有一个唯一的数字编号。这是必要的,因为在解析过程中,我们需要知道每个字段的顺序。在 .proto 文件中定义的每个字段都有默认值。例如,int32 类型的字段默认值为 0
  2. 字段类型:每个字段都有一个类型。例如,stringint32message 等。对于 message 类型的字段,你需要在括号内定义该消息的类型。对于 repeated 类型的字段,你可以将多个值放入一个列表中。例如,Person 消息中的 email 字段可以包含一个电子邮件地址列表。
  3. 服务调用:在客户端代码中,你可以使用生成的 stub 类来调用服务方法。例如,你可以这样调用 SayHello 方法:
HelloService.stub stub = HelloServiceGrpc.newBlockingStub(channel);
HelloReply response = stub.sayHello(HelloRequest.newBuilder().build());

在这里插入图片描述

关键字

Protocol Buffers(Protobuf)的关键字包括:

  1. message:代表实体结构,由多个消息字段(field)组成。
  2. required:表示该字段是必需的。
  3. optional:表示该字段是可选的。
  4. repeated:表示该字段的值是一个列表,可以包含0个或多个元素。
  5. group:用于组织多个字段,但目前该关键字已被废弃,应使用message。
  6. syntax:用于指定协议版本号,没有指定则默认为proto2版本。
  7. package:相等于C++中的命名空间,为了防止名称冲突。
  8. import:引入其他的proto文件,可以使用其他proto文件中定义的消息类型。
  9. message:用于定义消息类型,相当于C++中的struct。
  10. enum:用于定义枚举类型,相当于C++中的enum。
  11. option:用于设置消息字段的选项,如default、packed等。
  12. extensions:用于定义扩展消息字段,可以在现有消息类型的基础上添加新的字段。
  13. rpc:用于定义远程过程调用(RPC)服务。
  14. service:用于定义服务接口。
  15. default :用于为字段设置默认值。
  16. packed :用于指示字段值应该进行压缩存储。
  17. max :用于指定枚举类型的最大值。
  18. value :用于指定枚举类型的值。
  19. returns :用于指定RPC服务的返回类型。

这些关键字在Protobuf中具有特定的含义和用途,根据需要选择使用。

此外,Protobuf中的字段定义包括数据类型、字段名称、字段规则等部分。每个字段的定义由一定的格式构成,包括数据类型、字段名称、字段标识是必须定义的部分,字段默认值部分在proto3版本中不再支持。

在这里插入图片描述

JSON与Protocol Buffers互相转换

  • 与JSON的区别

Protocol Buffers与JSON的区别主要体现在以下三个方面:

  1. 数据格式:JSON是文本格式,而protobuf是二进制格式。JSON数据冗余较大,例如,每条记录都需要包含"CName"和"Gender",据统计,JSON格式的数据至少有20%左右是无效的。而protobuf用二进制编码数据,且数据的格式是事先通过一个后缀名为.proto的文件指定的,因此protobuf的数据信息相对较少。
  2. 解析速度:由于protobuf对message没有动态解析,没有了动态解析的处理序列化速度自然快,通常protobuf的序列化速度是JSON的10倍左右。
  3. 功能:JSON只是一种数据表示法,而protobuf则提供模式(类型),建立文档,强制正确的用法。

总的来说,JSON和protobuf在数据格式、解析速度和功能上存在明显差异。具体选择使用哪种数据存储格式,取决于具体的应用场景和需求。

  • 互相转换案例

在Java中,我们可以使用一些库来实现JSON与Protocol Buffers之间的相互转换。这里以Google的Protocol Buffers和Jackson库为例进行介绍。

首先,确保你的项目中已经添加了Protocol Buffers和Jackson的依赖。如果你使用Maven,可以在pom.xml文件中添加以下依赖:

<dependencies>
    <!-- Protocol Buffers -->
    <dependency>
        <groupId>com.google.protobuf</groupId>
        <artifactId>protobuf-java</artifactId>
        <version>3.17.3</version> <!-- 请检查是否有更新的版本 -->
    </dependency>
    <!-- Jackson -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.13.0</version> <!-- 请检查是否有更新的版本 -->
    </dependency>
</dependencies>
  1. Protocol Buffers转JSON

首先,我们需要将Protocol Buffers的消息转换为Java对象。假设我们有一个Person消息:

syntax = "proto3";
package tutorial;

message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;
}

编译这个.proto文件,生成Java代码。然后,我们可以使用Jackson库将Java对象转换为JSON:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.protobuf.util.JsonFormat;
import tutorial.PersonOuterClass.Person;

public class ProtobufToJsonExample {
    public static void main(String[] args) throws Exception {
        Person person = Person.newBuilder()
                .setId(1234)
                .setName("Alice")
                .setEmail("alice@example.com")
                .build();

        ObjectMapper objectMapper = new ObjectMapper();
        String jsonString = JsonFormat.printer().print(person);
        System.out.println(jsonString); // 输出JSON字符串
    }
}
  1. JSON转Protocol Buffers

同样地,我们可以将JSON字符串转换为Java对象后,再将其转换为Protocol Buffers消息:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.protobuf.util.JsonFormat;
import tutorial.PersonOuterClass.Person;

public class JsonToProtobufExample {
    public static void main(String[] args) throws Exception {
        String jsonString = "{\"id\":1234,\"name\":\"Alice\",\"email\":\"alice@example.com\"}";
        ObjectMapper objectMapper = new ObjectMapper();
        Person person = objectMapper.readValue(jsonString, Person.class);
        System.out.println(person); // 输出Person消息对象
    }
}

在Java中使用Protocol Buffers可以方便地进行数据序列化和反序列化。以下是一个简单的使用案例:

假设我们有一个Person消息类型,包含姓名、年龄和电子邮件地址等字段。我们可以使用Protocol Buffers的Java API来序列化和反序列化这个消息类型。

首先,我们需要定义Person消息类型的.proto文件,如下所示:

syntax = "proto3";

package tutorial;

message Person {
  string name = 1;
  int32 age = 2;
  string email = 3;
}

然后,我们需要使用Protocol Buffers的编译器protoc将.proto文件编译成Java代码。命令如下:

protoc --java_out=./ ./person.proto

这将生成一个PersonOuterClass.java和一个Person.java文件,其中Person.java包含Person消息类型的定义和相关方法。我们可以将这些代码导入到我们的Java应用程序中。

接下来,我们可以使用Java代码来序列化和反序列化Person消息类型。以下是一个简单的例子:

import tutorial.PersonOuterClass.Person;
import com.google.protobuf.util.JsonFormat;

public class PersonProtobufExample {
  public static void main(String[] args) throws Exception {
    // 创建一个Person对象
    Person person = Person.newBuilder()
        .setId(1234)
        .setName("Alice")
        .setEmail("alice@example.com")
        .build();

    // 将Person对象序列化为字节数组
    byte[] bytes = person.toByteArray();

    // 将字节数组反序列化为Person对象
    Person deserializedPerson = Person.parseFrom(bytes);

    // 输出反序列化后的Person对象
    System.out.println(deserializedPerson);
  }
}

这个例子中,我们创建了一个Person对象,将其序列化为字节数组,然后将字节数组反序列化为Person对象,并输出反序列化后的Person对象。

gRPC与Protocol Buffers的关系

Protocol Buffers(protobuf)是由 Google 开发的一种数据序列化协议(类似于 XML、JSON、YAML 等),它可以将结构化的数据序列化成字节流,以便在网络上进行传输或存储到文件或数据库中。

gRPC 是一个高性能、开源、通用的 RPC(远程过程调用)框架,它基于 protobuf 实现,使用 protobuf 序列化协议来序列化和反序列化消息。gRPC 支持多种语言,包括 Java、C++、Python、Go、Ruby、PHP 等,可以跨语言进行通信。

因此,gRPC 和 Protocol Buffers 的关系是,protobuf 是 gRPC 使用的一种数据序列化协议,gRPC 利用 protobuf 将数据序列化成字节流,以便在网络上进行传输或存储到文件或数据库中。同时,gRPC 也提供了接口和工具,使得用户可以方便地使用 protobuf 进行数据序列化和反序列化操作。

gRPC的简单介绍

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1217825.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

交换排序详讲:冒泡排序+快速排序(多方法+思路+图解+代码)

文章目录 交换排序一.冒泡排序二.快速排序1.挖坑法2.Hoare法 交换排序 根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置将键值较大的记录向序列的尾部移动&#xff0c;键值较小的记录向序列的前部移动。 一.冒泡排序 /*** 冒泡排序* 时间复杂度 n^2* 空间复杂…

用Postman发送xml数据

启动Postman&#xff1a; 点击左上角的“New”&#xff0c;在弹出窗中选择HTTP&#xff1a; 选择POST方法&#xff1a; 点击Body&#xff1a; 选择raw&#xff1a; 在右侧的下拉列表中选择XML&#xff1a; 在下面的输入框中输入或者从其它地方拷贝XML文本&#xff1a;…

cookie机制

目录 为什么会有cookie?? cookie从哪里来的&#xff1f;&#xff1f; cookie到哪里去&#xff1f;&#xff1f; cookie有啥用&#xff1f;&#xff1f; session HttpServletRequest类中的相关方法 简单的实现cookie登录功能 实现登录页面 实现servlet逻辑 实现生成主…

uni-app 蓝牙打印, CPCL指令集使用

先上代码: GitHub - byc233518/uniapp-bluetooth-printer-demo: 使用uniApp 连接蓝牙打印机 Demo, CPCL 指令简单实用示例 (内含 芝珂,佳博,精臣 多个厂家指令集使用文档) 文件结构: ├── App.vue ├── CPCL 指令手册.pdf // 指令集参考手册 ├── LICENSE ├── R…

【JAVA-排列组合】一个套路速解排列组合题

说明 在初遇排列组合题目时&#xff0c;总让人摸不着头脑&#xff0c;但是做多了题目后&#xff0c;发现几乎能用同一个模板做完所有这种类型的题目&#xff0c;大大提高了解题效率。本文简要介绍这种方法。 题目列表 所有题目均从leetcode查找&#xff0c;便于在线验证 46.…

Mindomo Desktop for Mac(免费思维导图软件)下载

Mindomo Desktop for Mac是一款免费的思维导图软件&#xff0c;适用于Mac电脑用户。它可以帮助你轻松创建、编辑和共享思维导图&#xff0c;让你的思维更加清晰、有条理。 首先&#xff0c;Mindomo Desktop for Mac具有直观易用的界面。它采用了Mac独特的用户界面设计&#xf…

2023年首届天府杯数学建模国际大赛问题A思路详解与参考代码:大地测量数据中异常现象的特征和识别

地球变形观测是固体潮汐曲线分析和地震前体研究的重要手段&#xff0c;也是地球观测技术的重要组成部分。基于各种精密科学仪器的变形观测点主要集中在洞穴、地下井等易的自然灾害&#xff08;雷暴、强降雨、降雪等&#xff09;&#xff0c;人工维护、人工爆破等外部条件&#…

浅谈安科瑞无线测温产品在巴西某工厂的应用

摘 要&#xff1a;高压开关设备是变电站和配电站中保证电力系统安全运行的重要设备之一,因此,开关柜的稳定运行对于整个电力系统有非常重要的意义。设备老化、长期高负荷运行都可能使设备局部温度过高而发生火灾&#xff0c;因此,对变电站内的敏感设备进行温度检测变得尤为重要…

chrome 浏览器个别字体模糊不清

特别是在虚拟机里&#xff0c;有些字体看不清&#xff0c;但是有些就可以&#xff0c;设置办法&#xff1a; chrome://settings/fonts 这里明显可以看到有些字体就是模糊的状态&#xff1a; 把这种模糊的字体换掉即可解决一部分问题。 另外&#xff0c;经过观察&#xff0c;…

Unity开发之C#基础-集合(字典)(Dictionary)

前言 Hello 兄弟们 一转眼俩月又过去了&#xff08;失踪人口回归&#xff09; 不出意外的是出意外了 失踪了两个月 有点对不起我这为数不多的粉丝们 实不相瞒忙的焦头烂额 也没心情写博客 实在对不住各位 好了长话短说 今天这篇文章是讲解c#当中的新的一种集合的表现&#xff…

​软考-高级-系统架构设计师教程(清华第2版)【第10章 软件架构的演化和维护(P345~382)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第10章 软件架构的演化和维护&#xff08;P345~382&#xff09;-思维导图】 课本里章节里所有蓝色字体的思维导图

idea运行项目之后一直卡在Writing classes… 解决方案

最近遇到idea里直接运行一个Spring boot项目后&#xff0c;idea一直慢悠悠的parsing java&#xff0c;然后就writing classes&#xff0c;然后就一直卡着不动了&#xff0c;运气好10几分钟能把项目启动起来。 多年的摸鱼经验告诉我&#xff0c;事出反常必有妖&#xff0c;赶紧…

python趣味编程-5分钟实现一个测验应用程序(含源码、步骤讲解)

Python测验是用 Python 编程语言编写的,这个关于 Python 编程的简单测验是一个简单的项目,用于测试一个人在给定主题考试中的知识能力。 Python 中的 Quiz项目仅包含用户端。用户必须先登录或注册才能开始Python 测验。 此外,还规定了解决问题的时间。用户应在时间结束前解…

Python---列表 集合 字典 推导式(本文以 字典 为主)

推导式&#xff1a; 推导式comprehensions&#xff08;又称解析式&#xff09;&#xff0c;是Python的一种独有特性。推导式是可以从一个数据序列构建另一个新的数据序列&#xff08;一个有规律的列表或控制一个有规律列表&#xff09;的结构体。 共有三种推导&#xff1a;列表…

系列七、JVM的内存结构【堆(Heap)】

一、概述 一个JVM实例只存在一个堆内存&#xff0c;堆内存的大小是可以手动调节的。类加载器读取了类文件后&#xff0c;需要把类、方法、常变量放到堆内存中&#xff0c;保存所有引用类型的真实信息&#xff0c;以方便执行器执行&#xff0c;堆内存分为三个部分&#xff0c;即…

人工智能基础_机器学习040_Sigmoid函数详解_单位阶跃函数与对数几率函数_伯努利分布---人工智能工作笔记0080

然后我们再来详细说一下Sigmoid函数,上面的函数的公式 我们要知道这里的,Sigmoid函数的意义,这逻辑斯蒂回归的意义就是,在多元线性回归的基础上,把 多元线性回归的结果,缩放到0到1之间对吧,根据中间的0.5为分类,小于0.5的一类,大于的一类, 这里的h theta(x) 就是概率函数 然…

python内置模块subprocess 模块,创建和管理子进程

一、简介 subprocess 是 Python 标准库中的一个模块&#xff0c;用于创建和管理子进程。它提供了一种在 Python 程序中启动新进程、连接到它们的输入/输出/错误管道以及获取它们的返回值的方法。 使用 subprocess 模块&#xff0c;你可以在 Python 程序中执行外部命令、调用其…

【第2章 Node.js基础】2.7 Node.js 的流(一) 可读流

&#x1f308; Node.js 的流 &#x1f680;什么是流 流不是 Node.js 特有的概念。它们是几十年前在 Unix 操作系统中引入的。 我们可以把流看作这些数据的集合&#xff0c;就像液体一样&#xff0c;我们先把这些液体保存在一个容器里&#xff08;流的内部缓冲区 BufferList&…

【Android】设置全局标题栏

序言 在做项目的时候&#xff0c;有时候需要一个全局统一的标题栏&#xff0c;保证项目风格的统一&#xff0c;但是如果在每个activity上面都写一遍这个标题栏就很麻烦了&#xff0c;我们经常用的方法就是写个基类Activity&#xff0c;然后当某个Activity需要这个统一的标题栏…

我记不住的getopt_long的那些参数和返回值

前言&#xff1a;最近在学习面向Linux系统进行C语言的编程&#xff0c;通过查询man手册和查看网络上的各种文章来获取一点点的知识&#xff0c;重点是看完手册还是一脸懵逼&#xff0c;搞不懂手册里面再说啥&#xff0c;而本篇文章将记录一下学习getopt_long的那些参数和返回值…