【Protobuf】Protobuf中的Message语法规范

news/2024/11/16 12:31:58/

Protobuf中的Message语法规范

  • Protobuf快速使用 Java版、Python版
  • 基本语法
    • 标识号
    • 选项
  • 字段类型
    • 枚举、数组、Map
  • 消息嵌套的几种写法
  • 消息嵌套的调用

Protobuf快速使用 Java版、Python版

  参考上一篇:点击查看

基本语法

syntax = "proto3";message MessageName {FieldType fieldName = fieldNumber;
}

  syntax指定使用的Protobuf版本。在这个示例中,使用的是Protobuf 3版本。

  代码定义了一个Message,名称为MessageName,可以根据需要自定义Message的名称。

  在Message中定义一个或者多个字段,FieldType是字段的数据类型,可以是基本类型(如int32stringbool等)或其他定义的Message类型。fieldName是字段的名称,可以根据需求自定义。fieldNumber是字段的唯一标识号,用于在消息的二进制编码中标识字段。

  例如:

syntax = "proto3";message Email{int32 id = 1;string name = 2;string emails = 3;
}

标识号

  在Protobuf中,每个字段都需要一个唯一的标识号(field number),用于在消息的二进制编码中标识该字段。标识号的作用是确保在消息的编解码过程中能够准确地识别每个字段。

  以下是关于标识号的一些重要点:

  标识号是一个正整数。
  标识号的范围是1到2^29 - 1(Protobuf 3版本中是1到536,870,911)。
  在同一个Message中,每个字段的标识号必须是唯一的。
  标识号的选择是自由的,但应保持一致性和稳定性,避免频繁变更标识号。
  在编码过程中,每个字段都会与其标识号一起被序列化到二进制数据中。接收方在解码时,通过读取二进制数据中的标识号来正确识别和解析每个字段的值。

[1,15]之内的标识号在编码的时候会占用一个字节。[16,2047]之内的标识号则占用2个字节。所以应该为那些频繁出现的消息元素保留 [1,15]之内的标识号。切记:要为将来有可能添加的、频繁出现的字段预留一些标识号。

  在Protobuf中,包package用于对消息类型进行组织和命名空间管理。包的作用是确保消息类型的唯一性,并避免命名冲突。

  示例:

syntax = "proto3";package com.example.mypackage;message Email{int32 id = 1;string name = 2;string emails = 3;
}

  通过使用包,可以在一个大型的Protobuf项目中组织消息类型,避免不同消息类型之间的命名冲突。同时,包还可以在生成的代码中生成对应的命名空间,以便在编程语言中进行访问和引用。

选项

  java_package:单独为java定义包名字。
  java_outer_classname:单独为java定义,protobuf编译器生成的类名。

syntax = "proto3";package com.example.mypackage;option java_package = "com.example.mypackage";
option java_outer_classname = "Email";message Email{int32 id = 1;string name = 2;string emails = 3;
}

字段类型

.proto TypeNotesC++ TypeJava TypePython Type[2]Go TypeRuby TypeC# TypePHP Type
double doubledoublefloatfloat64Floatdoublefloat
float floatfloatfloatfloat32Floatfloatfloat
int32使用变长编码,对于负值的效率很低,如果你的域有可能有负值,请使用sint64替代int32intintint32Fixnum 或者 Bignum(根据需要)intinteger
uint32使用变长编码uint32intint/longuint32Fixnum 或者 Bignum(根据需要)uintinteger
uint64使用变长编码uint64longint/longuint64Bignumulonginteger/string
sint32使用变长编码,这些编码在负值时比int32高效的多int32intintint32Fixnum 或者 Bignum(根据需要)intinteger
sint64使用变长编码,有符号的整型值。编码时比通常的int64高效。int64longint/longint64Bignumlonginteger/string
fixed32总是4个字节,如果数值总是比总是比228大的话,这个类型会比uint32高效。uint32intintuint32Fixnum 或者 Bignum(根据需要)uintinteger
fixed64总是8个字节,如果数值总是比总是比256大的话,这个类型会比uint64高效。uint64longint/longuint64Bignumulonginteger/string
sfixed32总是4个字节int32intintint32Fixnum 或者 Bignum(根据需要)intinteger
sfixed64总是8个字节int64longint/longint64Bignumlonginteger/string
bool boolbooleanboolboolTrueClass/FalseClassboolboolean
string一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。stringStringstr/unicodestringString (UTF-8)stringstring
bytes可能包含任意顺序的字节数据。stringByteStringstr[]byteString (ASCII-8BIT)ByteStringstring

枚举、数组、Map

  如下代码:

syntax = "proto3";message Staff {int32 id = 1;string name = 2;string email = 3;// 枚举示例enum PhoneType {MOBILE = 0;TELEPHONE = 1;}// 嵌套示例message PhoneNumber {string number = 1;PhoneType type = 2;}// list示例// 只要使用repeated标记类型定义,就表示数组类型。repeated PhoneNumber phone = 4;message Map {string key = 1;int32 value = 2;}// map示例Map map = 5;
}

消息嵌套的几种写法

  1、引用写法

// 定义Result消息
message Result {string url = 1;string title = 2;repeated string snippets = 3; // 字符串数组类型
}// 定义SearchResponse消息
message SearchResponse {// 引用上面定义的Result消息类型,作为results字段的类型repeated Result results = 1; // repeated关键词标记,说明results字段是一个数组
}

  2、嵌套写法

message SearchResponse {// 嵌套消息定义message Result {string url = 1;string title = 2;repeated string snippets = 3;}// 引用嵌套的消息定义repeated Result results = 1;
}

  3、import写法

  在开发一个项目的时候通常有很多消息定义,都写在一个proto文件,不方便维护,通常会将消息定义写在不同的proto文件中,在需要的时候可以通过import导入其他proto文件定义的消息。

   result.proto

syntax = "proto3";
// Result消息定义
message Result {string url = 1;string title = 2;repeated string snippets = 3; // 字符串数组类型
}

  search_response.proto

syntax = "proto3";
// 导入Result消息定义
import "result.proto";// 定义SearchResponse消息
message SearchResponse {// 使用导入的Result消息repeated Result results = 1; 
}

消息嵌套的调用

  注意在调用消息时,要先调用嵌套消息:

  消息定义:

syntax = "proto3";message Staff {int32 id = 1;string name = 2;string email = 3;// 枚举示例enum PhoneType {MOBILE = 0;TELEPHONE = 1;}// 嵌套示例message PhoneNumber {string number = 1;PhoneType type = 2;}// list示例// 只要使用repeated标记类型定义,就表示数组类型。repeated PhoneNumber phone = 4;message Map {string key = 1;int32 value = 2;}// map示例Map map = 5;
}

  调用写法:

public static void main(String[] args) {//  序列化// 创建Result的BuilderStaffbuf.Staff.Builder staffBuilder = Staffbuf.Staff.newBuilder();staffBuilder.setId(1);staffBuilder.setName("张三丰");//staffBuilder.setEmail("zhangsanfeng@wudang.org");// 构建引用消息(import message)PhoneNumberList list = new ArrayList();PhoneNumberBuf.PhoneNumber.Builder phoneBuilder =PhoneNumberBuf.PhoneNumber.newBuilder();phoneBuilder.setType(PhoneNumberBuf.PhoneNumber.PhoneType.TELEPHONE);phoneBuilder.setNumber("010-12345678");PhoneNumberBuf.PhoneNumber phoneNumber = phoneBuilder.build();list.add(phoneNumber);phoneBuilder.clear();phoneBuilder.setType(PhoneNumberBuf.PhoneNumber.PhoneType.MOBILE);phoneBuilder.setNumber("13912345678");list.add(phoneBuilder.build());staffBuilder.addAllPhone(list);// 完成staff的构建Staffbuf.Staff zhangsanfeng = staffBuilder.build();// 序列化,byte[]可以被写到磁盘文件,或者通过网络发送出去。byte[] data = zhangsanfeng.toByteArray();System.out.println("serialization end.");// 反序列化,byte[]可以读文件或者读取网络数据构建。System.out.println("deserialization begin.");try {Staffbuf.Staff staff = Staffbuf.Staff.parseFrom(data);System.out.println(staff.getId());System.out.println(staff.getName());staff.getPhoneList().forEach(x -> System.out.println(x.toString()));} catch (InvalidProtocolBufferException e) {e.printStackTrace();}}

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

相关文章

2612硒鼓拆装加粉

好久没有写文章了,和之前年初的时候说要在这里记录所以一些知识文档有一点了违被了,都过这么久了也该把我09年03月到09月所发生,所了解的知识做一记录. 3月17日 拆装2612硒鼓型号 先发个图上来吧. 结构:分为两边. 一边: 鼓芯,橡胶棒,废粉仓. 另一边: 粉盒,充电辊. 拆装…

清除三星SCX4200硒鼓上的计数器

注意4200机器分英文版机器和中文版机器2种,芯片里的资料也是不一样的,二种不能互换.附件里提供的是中文版用的,英文版机器的朋友不要用. 下面的线路板拆开硒鼓后就可以看见,如果不拆鼓只能看到 GND,CLK,DATA,VCC四个触点(外边只能看到3段金属丝,隐约可以看到板子上印的字) 记数…

三星SCX-4521F 4725F内存接收墨粉用尽问题

三星传真机SCX-4521F硒鼓粉终于耗尽,加粉后,还是提示“粉墨耗尽”,打印/复印正常,但是传真机功能不能使用,只处于内存接收状态。查看了一下,保险丝是85mA的,手头没这规格的,就没换&a…

java的内部类

1.内部类的概念 内部类表示的事物是外部类的一部分,内部类单独出现没有任何意义。如发动机是汽车的一部分。 内部类的访问特点: (1)内部类可以直接访问外部类的成员,包括私有; (2)外…

仿真用计算机配置,需要进行仿真,选什么配置的电脑比较好

满意答案 yang851221 2019.10.18 采纳率:40% 等级:8 已帮助:309人 楼主你好,你没说预算不敢给你配太贵的…不多说,请看配置:主板:映泰th616.x价格:¥599要稳定和性价比…

iphone11各机型对比_iPhone 11系列配置规格对比 快来看看哪款最适合你

【手机中国新闻】日前,苹果正式宣布,将于美国当地时间9月10日上午举办秋季新品发布会,发布全新iPhone产品。不出意外的话,就是之前曝光的iPhone 11系列,至少有iPhone 11、iPhone 11 Pro、iPhone 11 Pro MAX三款新品。9…

荣耀x10和荣耀20pro哪个好?参数配置对比介绍

荣耀x10和荣耀20pro哪个好? 屏幕尺寸的话,荣耀x10比较大,单手难操控,荣耀20pro单手握持感比较好;最大的不同就是x10是升降摄像头,而20pro是挖孔,从屏幕观感来讲x10会更好,但是整台机器会更重; 来源&#…

使用IPSW文件将iOS系统从Beta恢复到稳定正式版教程

起因 作为一名iOS开发者,为了拥抱新系统(手贱),将开发机升级到了最新的iOS 17 Beta版本,从而导致使用现有的Xcode无法成功配对该版本系统。故准备想方设法回滚到原先的iOS 16.5稳定版 回滚方式 若要将iOS设备回退至…