Protobuf:基本概念与使用流程

news/2024/9/24 6:12:43/

Protobuf:基本概念与使用流程

    • 基本概念
    • Linux 安装
    • 使用流程
      • .proto文件
      • 编译
      • 使用
    • 运行机制


基本概念

在进行网络编程时,经常需要进行数据传输,只有双方主机都保证数据格式的一致性,才能保证数据被正常解析。这个过程称为序列化反序列化,当前主流的标准有jsonxml等,而protobuf就是其中一个数据格式的标准。

jsonxml都是人类可视化的序列化形式,存储的都是字符串,哪怕没有程序解析都可以直接读取。

比如一个Person类,分别用jsonxml序列化的结果:

json

{"name" : "John Doe","age" : 30,"email" : "john.doe@example.com"
}

xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Person><name>John Doe</name><age>30</age><email>john.doe@example.com</email>
</Person>

哪怕没有学习过相关语法,也可以很容易读取出序列化后的内容所包含的信息。

protobuf存储的方式则是二进制形式,序列化后无法直接读取,只能看到乱码,必须由程序完成解析。相应的,protobuf的效率会比上面两者高很多,因为protobuf对数据的压缩效率极高,牺牲可视化换取高效,在一些需要高效传输数据的场景很有用。

一个序列化相关的协议,想要在计算机语言中使用,自然要配备相关的库,比如JavaScript原生对json的支持,C++通过jsoncpp库对json的支持。

protobuf由谷歌开发,谷歌也编写了相关的库,其可以支持C++JavaPythonGoC#JavaScriptPHP等主流语言,本博客以C++讲解protobuf


Linux 安装

ubuntu为例,接下来讲解如何在Linux上安装protobuf

  1. 安装依赖库

protobuf有很多依赖的库文件,执行以下指令下载所有所需的库:

apt-get install autoconf automake libtool curl make g++ unzip -y

如果是centOS,则把apt-get换成yum,另外的需要root权限。

  1. 下载安装包

protobuf的下载连接:

https://github.com/protocolbuffers/protobuf/releases

在页面中,会有很多的版本,每个版本下面的assert内有如下的安装包:

在这里插入图片描述

此时根据自己的系统架构,以及想要的版本选择对应的安装包,比如Linux x86_64架构,安装28.2版本,执行:

wget https://github.com/protocolbuffers/protobuf/releases/protoc-28.2-linux-x86_64.zip

当然也有很多其他方式,只要获取到压缩包就行。

  1. 解压安装包

最常见的安装位置是/usr/local/bin,里面存储了很多可执行文件,创建一个protobuf的目录,用于存放对应的可执行文件:

mkdir -p /usr/local/bin/protoc

随后把压缩包的内容解压到对应目录下:

unzip protoc-28.2-linux-x86_64.zip -d /usr/local/bin/protoc
  1. 添加环境变量

为了protobuf可以直接执行,要把protobufbin的路径添加到PATH环境变量中,打开~/.bashrc文件,追加以下语句到末尾:

export PATH=$PATH:/usr/local/bin/protoc/bin

最后重新加载配置文件:

source ~/.bashrc
  1. 检查安装
protoc --version

如果出现对应的版本号,那么安装成功了。


使用流程

.proto文件

就像C语言基于.c文件,C++基于.cpp文件,protobuf是基于.proto文件使用的。在.proto文件内部基于proto3语法编写文档,就可以自动生成其他语言的代码。

创建一个test.proto文件,在内部写以下内容:

syntax = "proto3";
package test_pack;message Person {string name = 1;int32 age = 2;
}// 一条注释

.proto文件基本格式如下:

  1. 语法指定行

首行固定为语法指定行,用于指定protobuf的语法版本,格式:

syntax = "版本号";

目前最新的版本为proto3,填入:

syntax = "proto3";

注意一定要在首行,哪怕上面有空行也不行,否则无法编译。

  1. package命名空间

package是一个命名空间,可以避免命名冲突,类似于C++中的namespace或者Java中的package。这是一个可选项,如果不怕命名冲突,也可以不指定。

语法:

package 命名空间;
  1. message 消息

message用于定义一个结构化的对象,其实就是一个class,内部可以定义成员。

成员字段的格式如下:

类型 成员名 = 标签;

具体类型比较多,会有专门的博客讲解protobuf的类型。标签protobuf压缩数据的重要方式,就是给每个变量指定一个编号,后续会专门讲解该内容。

标签范围: [ 1 , ( 2 29 − 1 ) ] [1, (2^{29} - 1)] [1,(2291)]

其中[19000, 19999]不可用,是保留的编号。

解析:

message Person {string name = 1;int32 age = 2;
}
  • name:字符串类型,标签为1
  • age:32位整型,标签为2

学过任何一门面向对象语言,这些内容都很好理解。

  1. 注释

.proto文件中注释格式有两种:

// 行注释/* 块注释 */

另外的,注释不占行数,也就是说首行可以是注释,不会影响syntax指定的语法标准:

// 注释...
// 注释...
// 注释...
syntax = "proto3";

以上写法是合法的,syntax前面可以有注释,但不能有空行或其他内容。


编译

编写好一个基本的.proto文件后,就可以对其进行编译,需要通过protoc指令:

protoc [--proto_path=improt路径] --cpp_out=目标路径 源路径.proto
  1. --proto_path:指定 .proto 文件的搜索路径

.proto文件中,可以通过import导入其它的.proto文件,此时就需要通过--proto_path来指定其他文件的查找路径,否则无法找到文件。

  1. --cpp_out=目标路径

--cpp_out用于指定输出C++语言的代码,目标路径是生成的代码的位置。

其他语言的选项:

选项描述
--cpp_out指定生成 C++ 代码的目录
--java_out指定生成 Java 代码的目录
--python_out指定生成 Python 代码的目录
--csharp_out指定生成 C# 代码的目录
--go_out指定生成 Go 代码的目录
--js_out指定生成 JavaScript 代码的目录
--objc_out指定生成 Objective-C 代码的目录
--php_out指定生成 PHP 代码的目录
--ruby_out指定生成 Ruby 代码的目录
--grpc_out指定生成 gRPC 服务端和客户端代码的目录
--grpc_java_out指定生成 Java gRPC 代码的目录
--swift_out指定生成 Swift 代码的目录
  1. 源文件路径

最后再指定xxx.proto源文件的路径。

如果是C++,编译后会产生如下文件:

在这里插入图片描述

至少产生了xxx.pb.ccxxx.pb.h,这些就是生成的C++代码,后续可以直接使用内部的接口。


使用

xxx.pb.h文件中至少可以找到以下内容:

namespace test_pack {class Person final : public ::google::protobuf::Message
/* @@protoc_insertion_point(class_definition:test_pack.Person) */ {public:inline Person() : Person(nullptr) {}~Person() PROTOBUF_FINAL;// ...}
}

可以看到一个命名空间域namespace test_pack,这就是之前在.proto文件中写的package test_pack,最后转化为了C++的命名空间域。

message Person也转化为了class Person,其内部实现了大量接口,包含getset等方法,以及序列化和反序列化接口。


运行机制

至此也可以看出protobuf具体是如何运行的了,如下图:

在这里插入图片描述

使用protobuf需要编写.proto文件,随后通过protoc编译器编译.proto文件,就可以得到对应语言的文件。在对应语言的文件中,会包含各类接口,最重要的就是序列化和反序列化。

.proto文件中,会有很多和计算机语言具体对应的概念,比如message对应类,package对应命名空间域,或者其他语言的包。他们都会在编译器的作用下,自动转化成对应的语言。

最后只要往自己的业务代码中引入文件,比如#include "xxx.pb.h",或者其他语言的import等,就可以直接在业务代码中使用protobuf了。



http://www.ppmy.cn/news/1529683.html

相关文章

PDF里怎么直接编辑文字?简单操作指南

PDF作为一种广泛使用的文档格式&#xff0c;因其稳定性和跨平台兼容性而受到欢迎。然而&#xff0c;PDF原生的编辑功能相对有限&#xff0c;尤其是直接编辑其中的文字。但幸运的是&#xff0c;随着技术的发展&#xff0c;我们现在有几种方法可以在PDF中直接编辑文字。在本文中&…

JS巧用.padStart()|.padEnd()方法用另一个字符串填充当前字符串

示例 const sortNum computed(() > No.${${1}.padStart(2, 0)}); // No.01const sortNum computed(() > No.${${1}.padEnd(2, 0)}); // No.10 padStart .padStart() 方法可以用于添加一个字符串作为填充&#xff0c;以使当前字符串达到所需的长度。例如&#xff0c;…

Vue开发前端图片上传给java后端

前端效果图 图片上传演示 1 前端代码 <template><div><!-- 页面标题 --><h1 class"page-title">图片上传演示</h1><div class"upload-container"><!-- 使用 van-uploader 组件进行文件上传&#xff0c;v-model 绑…

开关电源自动测试系统的测试设备与特色

突破传统测试系统的操作维护困难等限制&#xff0c;NSAT-8000开关电源自动测试系统以其开放式架构和0代码模式&#xff0c;带来了不一样的开关电源自动化测试体验。 开关电源自动测试系统的测试设备 开关电源自动测试系统核心硬件包括&#xff1a;可编程交直流电源、电子负载、…

【技术解析】wx.request 封装:优化小程序网络请求的最佳实践

在当今的小程序开发领域&#xff0c;网络请求是构建动态应用的核心。微信小程序提供的 wx.request API 虽然强大&#xff0c;但在面对复杂业务逻辑时&#xff0c;其直接使用方式可能会带来一系列问题。本文将深入探讨封装 wx.request 的必要性&#xff0c;并提供一套实用的封装…

java.nio.ByteBuffer的 capacity, limit, position, mark

java.nio.ByteBuffer的 capacity, limit, position, mark Capacity&#xff08;容量&#xff09; 定义&#xff1a;缓冲区的总容量&#xff0c;即缓冲区中可以容纳的元素的数量。这个容量在缓冲区创建时被设定&#xff0c;并且之后不能被改变。 用途&#xff1a;它定义了缓冲区…

【ShuQiHere】 探索数据挖掘的世界:从概念到应用

&#x1f310; 【ShuQiHere】 数据挖掘&#xff08;Data Mining, DM&#xff09; 是一种从大型数据集中提取有用信息的技术&#xff0c;无论是在商业分析、金融预测&#xff0c;还是医学研究中&#xff0c;数据挖掘都扮演着至关重要的角色。本文将带您深入了解数据挖掘的核心概…

Android 用线程池实现一个简单的任务队列(Kotlin)

关于线程池,Kotlin和java的使用方式一样 在Android中,很多人喜欢用Handler的postDelayed() 去实现延时任务. 要使用postDelayed(),去实现延时任务队列,就不可避免要使用递归. 但是这样做,代码的简洁性,和书写的简易,就远不如使用线程池. 使用线程池的简单程度: private val…