protobuf的复杂结构

前言

在写proto文件的时候,想要百度一下都有哪些内容,但是找到的都是那个经典的官方样例,互相之间抄来抄去,所以这里干脆把git上的相关源码,和实际使用经历结合总结下来,给一潭死水里注入一点活力吧。

常用关键字

1. syntax:指定proto文件使用的语法版本。
2. package:指定生成的代码所在的包名。
3. import:导入其他proto文件。
4. option:设置特定的选项。
5. message:定义消息类型。
6. enum:定义枚举类型。
7. service:定义服务接口。
8. rpc:定义远程过程调用方法。
9. oneof:定义互斥字段,只能选择其中一个字段。
10. map:定义映射类型,类似于字典。
11. repeated:定义重复字段,可以有多个值。
12. required:定义必需字段,必须有值。
13. optional:定义可选字段,可以有值也可以为空。
14. extensions:定义扩展字段。
15. extend:扩展已有的消息类型或枚举类型。

每个关键字的使用示例

  1. syntax:
syntax = "proto3";
  1. package:
package mypackage;
  1. import:
import "google/protobuf/timestamp.proto";
  1. option:
option java_package = "com.example.mypackage";
  1. message:
message Person {
  string name = 1;
  int32 age = 2;
  repeated string phone_numbers = 3;
}
  1. enum:
enum PhoneType {
  MOBILE = 0;
  HOME = 1;
  WORK = 2;
}
  1. service:
service MyService {
  rpc GetData (GetDataRequest) returns (GetDataResponse);
}
  1. rpc:
rpc GetData (GetDataRequest) returns (GetDataResponse);
  1. oneof:
message Person {
  string name = 1;
  oneof phone_number {
    string mobile = 2;
    string home = 3;
    string work = 4;
  }
}
  1. map:
message Person {
  string name = 1;
  map<string, string> phone_numbers = 2;
}
  1. repeated:
message Person {
  string name = 1;
  repeated string phone_numbers = 2;
}
  1. required:
message Person {
  required string name = 1;
  required int32 age = 2;
}
  1. optional:
message Person {
  optional string name = 1;
  optional int32 age = 2;
}
  1. extensions:
extend Person {
  extensions 100 to 199;
  optional string email_address = 100;
}
  1. extend:
extend google.protobuf.Timestamp {
  optional string timezone = 1000;
}

复杂结构

下面是一些示例,展示了proto文件中的嵌套、数组和以结构体为值的映射的用法:

  1. 嵌套示例:
syntax = "proto3";

message Address {
  string street = 1;
  string city = 2;
  string state = 3;
}

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

在上面的示例中,Address是一个嵌套在Person中的消息类型。

  1. 数组示例:
syntax = "proto3";

message Person {
  string name = 1;
  repeated string phone_numbers = 2;
}

在上面的示例中,phone_numbers字段是一个字符串数组。

  1. 以结构体为值的映射示例:
syntax = "proto3";

message Person {
  string name = 1;
  map<string, Address> addresses = 2;
}

message Address {
  string street = 1;
  string city = 2;
  string state = 3;
}

在上面的示例中,addresses字段是一个以字符串为键、Address结构体为值的映射。

  1. 自定义枚举值:
syntax = "proto3";

enum PhoneType {
  MOBILE = 0;
  HOME = 1;
  WORK = 2;
  CUSTOM = 3;
}

在上面的示例中,我们定义了一个自定义的枚举值CUSTOM。

  1. 扩展字段:
syntax = "proto3";

message Person {
  string name = 1;
  extensions 100 to 199;
}

extend Person {
  optional string email = 100;
}

在上面的示例中,我们使用extend关键字扩展了Person消息类型,添加了一个可选的email字段。

  1. 服务定义和RPC方法:
syntax = "proto3";

service MyService {
  rpc GetData (GetDataRequest) returns (GetDataResponse);
  rpc UpdateData (UpdateDataRequest) returns (UpdateDataResponse);
}

message GetDataRequest {
  string id = 1;
}

message GetDataResponse {
  string data = 1;
}

message UpdateDataRequest {
  string id = 1;
  string newData = 2;
}

message UpdateDataResponse {
  bool success = 1;
}

在上面的示例中,我们定义了一个名为MyService的服务,其中包含了两个RPC方法:GetData和UpdateData。每个RPC方法都有对应的请求消息和响应消息。


分享一个有趣的 学习链接:https://xxetb.xet.tech/s/HY8za

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要在 C++ 中还原 Protobuf 结构,你需要按照以下步骤进行操作: 1. 定义 Protobuf 的消息结构:在 .proto 文件中定义 Protobuf 的消息结构,并使用 Protocol Buffer 编译器生成 C++ 代码文件。 2. 包含头文件:在 C++ 代码中包含生成的头文件。 3. 创建消息对象:使用生成的类创建一个消息对象。 4. 设置消息内容:使用消息对象的 setter 方法设置消息的内容。 5. 序列化:将消息对象序列化为字节流。 6. 反序列化:将字节流反序列化为消息对象。 以下是一个简单的示例代码: ```c++ #include <iostream> #include "person.pb.h" // 包含生成的头文件 int main() { // 创建一个 Person 对象 Person person; person.set_name("Alice"); person.set_id(123); person.set_email("[email protected]"); // 序列化 std::string data; person.SerializeToString(&data); // 反序列化 Person person2; person2.ParseFromString(data); // 输出反序列化后的消息内容 std::cout << "Name: " << person2.name() << std::endl; std::cout << "ID: " << person2.id() << std::endl; std::cout << "Email: " << person2.email() << std::endl; return 0; } ``` 在上述代码中,我们使用了名为 `Person` 的消息结构,并使用 Protocol Buffer 编译器生成了 C++ 代码文件 `person.pb.h`。在 `main` 函数中,我们创建了一个 `Person` 对象并设置了它的内容,然后将它序列化为字节流。接着,我们将字节流反序列化为另一个 `Person` 对象,并输出它的内容。 ### 回答2: 谢谢你的问题。Protobuf 是一种二进制数据序列化格式,用于在不同的系统之间传输和存储结构化数据。如果要还原 Protobuf 结构,你需要了解数据的类型和字段定义。以下是一个示例: 假设我们有一个 Protobuf 定义的消息结构,包含一个名称和年龄字段: ```protobuf message Person { string name = 1; int32 age = 2; } ``` 在这个示例中,`Person` 是一个消息类型,拥有两个字段:`name` 和 `age`。`name` 字段的类型是字符串,字段标识号是 1;`age` 字段的类型是整数,字段标识号是 2。 如果我们从一个二进制数据中还原 Protobuf 结构,我们可以按照如下步骤进行: 1. 解析二进制数据,将其转换为可读的消息结构; 2. 查找字段的标识号,找到对应的字段类型; 3. 根据字段类型解析字段的值; 4. 重复以上步骤,直到解析完整个消息结构。 对于上述示例,如果我们有一个二进制数据 `080512546f6d0810`,我们可以进行如下还原: 1. 将二进制数据转换为十六进制:`08 05 12 54 6f 6d 08 10`; 2. 将十六进制解析为字段标识号和字段类型:`08` 表示字段标识号 1,类型为字符串;`05` 表示字段长度为 5; 3. 将剩余的十六进制解析为字段标识号和字段类型:`12` 表示字段标识号 2,类型为变长整数;`54 6f 6d` 表示字段值为字符串 "Tom"; 4. 完成解析,得到还原后的结构:`name: "Tom", age: 16`。 这只是一个简单的示例,实际情况可能更加复杂,特别是对于包含嵌套结构或者重复字段的消息。还原 Protobuf 结构需要对消息定义有深入的了解,并按照消息定义的规则进行解析。 ### 回答3: protobuf是一种用于序列化结构化数据的语言无关、平台无关、可扩展的协议。结构体是一种将多个不同类型的变量组合成一个单独的数据单元的方式。还原protobuf结构指的是根据protobuf的定义,将序列化后的数据转换为原始的结构体。 要还原protobuf结构,首先需要了解protobuf的定义文件,也就是.proto文件。这个文件使用一种简单的语法定义了消息类型以及消息中的字段。每个字段都有一个唯一的标识符和类型。 接下来,我们需要使用protobuf的编译器将.proto文件编译成对应的源代码。编译器提供了各种编程语言的支持,例如Java、C++等。编译生成的源代码包含了定义的消息类型和字段的具体实现。 在得到编译生成的源代码后,我们可以使用相应的编程语言来操作protobuf数据。首先,我们需要将序列化后的数据转换成字节流。然后,使用protobuf提供的库函数,将字节流解析成对应的消息对象。解析后,就可以通过访问消息对象的字段来获取原始数据。 需要注意的是,还原protobuf结构的前提是要有对应的.proto文件以及生成的源代码。没有这些信息,是无法还原protobuf结构的。因此,在进行protobuf消息的序列化和反序列化时,一定要确保.proto文件与生成的源代码的一致性。 总结起来,还原protobuf结构可以通过以下步骤实现:了解.protobuf文件的定义 -> 使用protobuf编译器生成源代码 -> 将序列化后的数据转换成字节流 -> 使用protobuf库函数解析字节流 -> 访问消息对象的字段获取原始数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值