前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【Protobuf协议】001-Protobuf概述、定义Message类型

【Protobuf协议】001-Protobuf概述、定义Message类型

作者头像
訾博ZiBo
发布2025-01-06 17:20:15
发布2025-01-06 17:20:15
13800
代码可运行
举报
运行总次数:0
代码可运行

一、概述

1、Protobuf

Protobuf是Protocol Buffers的简称,它是Google公司开发的一种数据描述语言,用于描述一种轻便高效的结构化数据存储格式,并于2008年对外开源。Protobuf可以用于结构化数据串行化,或者说序列化。它的设计非常适用于在网络通讯中的数据载体,很适合做数据存储或 RPC 数据交换格式,它序列化出来的数据量少,再加上以 K-V 的方式来存储数据,对消息的版本兼容性非常强,可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。开发者可以通过Protobuf附带的工具生成代码并实现将结构化数据序列化的功能;

官方文档:https://developers.google.com/protocol-buffers/docs/proto3

2、序列化与反序列化

序列化(编码)是将对象序列化为二进制形式(字节数组),主要用于网络传输、数据持久化等;

反序列化(解码)则是将从网络、磁盘等读取的字节数组还原成原始对象,主要用于对网络传输对象的解码,以便完成远程调用;

3、数据描述语言

百度百科

数据描述语言,DDL(Data Description Language):是一种允许产生新的描述方案(DS)和描述符(D)的语言,它也允许现存描述方案的扩充和修正。在此基础上,用户就可以根据需要自己来定义新的描述方案和描述符。常见的数据描述语言有:SGML、HTML、XML等;

4、结构化数据

如字面含义,就是带有一定结构的数据。比如一个学生的信息,有学号、姓名、性别、年龄等;

这让我想起关系型数据库:关系型数据库按照结构化的方法存储数据;

5、与xml、json相比

xml、json也可以用来存储此类结构化数据,但是使用protobuf表示的数据更加高效,并且将数据压缩得更小,大约是json格式的1/10,xml格式的1/20;

二、定义Message类型

从这里就跟着官方文档走了

1、简单案例

Message

是Protobuf中最基本的数据单元,是类似Go语言中结构体的存在。在message中可以嵌套message或其它的基础数据类型的成员。

我目前看来类似Java中的类

一个简单的.proto文件案例
代码语言:javascript
代码运行次数:0
复制
syntax = "proto3"; // 指定protobuf版本,默认为proto2,必须在文件的第一行

message Student {
    // 下面的编号1、2、3并不需要按照一定顺序,只要是唯一的就行
	int32 id = 1; // id
	string name = 2; // 名字
	int32 age = 3; // 年龄
}

2、指定字段类型

上面的例子中,我们指定了两个int32类型和一个string类型,这些都是标准类型,也可以指定枚举类型其他Message类型

3、分配字段编号

上面我们定义字段的时候都使他们等于唯一的一个数字,这些数字并不需要按照一定的顺序写!

这些字段编号用于以消息二进制格式标识字段,在使用消息类型后不应更改。注意,范围1到15中的字段编号需要一个字节进行编码,包括字段编号和字段类型(您可以在 Protocol Buffer Encoding 中找到更多相关信息)。范围16到2047的字段编号采用两个字节。因此,应该为经常出现的消息元素保留数字1到15。记住为将来可能添加的频繁出现的元素留出一些空间。

4、指定字段规则

singular(默认):单个,可以有0个或者1个;

repeated:重复,相当于数组,可以有0个或者多个;

5、添加更多Message类型

多个消息类型能够写在一个.proto文件中;

如果您正在定义多个相关的消息,这是非常有用的!

代码语言:javascript
代码运行次数:0
复制
message SearchRequest {
    string query = 1;
    int32 page_number = 2;
    int32 result_per_page = 3;
}

message SearchResponse {
	...
}

6、添加注释

可以像Java、C/C++、JavaScript等,使用 // 和 /* ... */ 进行注释;

7、预留字段

指定预留的字段名字和编号,阻止它们被使用!

代码语言:javascript
代码运行次数:0
复制
message Foo {
    reserved 2, 15, 9 to 11;
	reserved "foo", "bar";
}

如果您通过完全删除字段或将其注释掉来更新消息类型,那么未来的用户在对该类型进行自己的更新时可以重用这些字段号。如果他们以后加载同一.proto文件的旧版本,这可能会导致严重的问题,包括数据损坏,隐私漏洞等等。确保这种情况不会发生的一种方法是指定保留已删除字段的字段编号(或名称,这也可能导致 JSON 序列化问题)。此后,如果任何未来的用户试图使用这些字段标识符,协议缓冲区编译器将发出警示。 注意,不能在同一个保留语句中混合字段名和字段编号。

8、你的.proto文件生成了什么

当你使用protobuf编译器对.proto文件进行编译的时候,编译器将生成你所选语言的代码、你将需要处理的消息类型、你在文件中的描述,代码包括getter和setter方法,将消息序列化到输出流的方法以及从输入流解析消息的方法;

支持的语言:C++、Java、Python、Go、Ruby、Objective-C、C#、Dart、JavaScript等;

  • 对C++来说,编译器会为每个.proto文件生成一个.h文件和一个.cc文件,.proto文件中的每一个消息有一个对应的类;
  • 对Java来说,编译器为每一个消息类型生成了一个.java文件,以及一个特殊的Builder类(该类是用来创建消息类接口的);
  • 对Python来说,有点不太一样——Python编译器为.proto文件中的每个消息类型生成一个含有静态描述符的模块,该模块与一个元类(metaclass)在运行时(runtime)被用来创建所需的Python数据访问类;
  • 对go来说,编译器会位每个消息类型生成了一个.pd.go文件;
  • 对于Ruby来说,编译器会为每个消息类型生成了一个.rb文件;
  • javaNano来说,编译器输出类似域java但是没有Builder类;
  • 对于Objective-C来说,编译器会为每个消息类型生成了一个pbobjc.h文件和pbobjcm文件,.proto文件中的每一个消息有一个对应的类;
  • 对于C#来说,编译器会为每个消息类型生成了一个.cs文件,.proto文件中的每一个消息有一个对应的类;
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-01-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、概述
    • 1、Protobuf
    • 2、序列化与反序列化
    • 3、数据描述语言
    • 4、结构化数据
    • 5、与xml、json相比
  • 二、定义Message类型
    • 1、简单案例
      • Message
      • 一个简单的.proto文件案例
    • 2、指定字段类型
    • 3、分配字段编号
    • 4、指定字段规则
    • 5、添加更多Message类型
    • 6、添加注释
    • 7、预留字段
    • 8、你的.proto文件生成了什么
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档