首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Protocol Buffers (Protobuf) 详解

Protocol Buffers (Protobuf) 详解

原创
作者头像
木易士心
修改2025-11-19 07:58:57
修改2025-11-19 07:58:57
4200
举报

Protocol Buffers (Protobuf) 详解

1. 什么是 Protocol Buffers?

Protocol Buffers(简称 Protobuf)是 Google 开发的一种**语言无关、平台无关、可扩展**的序列化数据结构的机制。它比 XML 和 JSON 更小、更快、更简单。

2. 核心特性

2.1优点

  • **高效性**:二进制格式,体积小,序列化/反序列化速度快
  • **跨语言**:支持多种编程语言
  • **向前/向后兼容**:通过字段编号机制实现
  • **代码生成**:自动生成数据访问类
  • **结构化数据**:强类型定义

2.2 缺点

  • **可读性差**:二进制格式不易阅读
  • **需要预编译**:需要预定义 .proto 文件

3. 基本语法

3.1 基本消息定义

代码语言:protobuf
复制
syntax = "proto3";



message Person {

  string name = 1;

  int32 id = 2;

  string email = 3;

  

  enum PhoneType {

    MOBILE = 0;

    HOME = 1;

    WORK = 2;

  }

  

  message PhoneNumber {

    string number = 1;

    PhoneType type = 2;

  }

  

  repeated PhoneNumber phones = 4;

}

3.2 字段规则

  • singular: 单个值(默认)
  • repeated: 数组/列表
  • map<K, V>: 键值对

3.3 数据类型

| .proto 类型 | C++ 类型 | Java 类型 | Python 类型 |

|------------|----------|-----------|-------------|

| double | double | double | float |

| float | float | float | float |

| int32 | int32 | int | int |

| int64 | int64 | long | int/long |

| bool | bool | boolean | bool |

| string | string | String | str |

| bytes | string | ByteString| bytes |

4. 版本差异

proto2 vs proto3

代码语言:protobuf
复制
// proto2

syntax = "proto2";

message Example {

  required string name = 1;    // 必须字段

  optional int32 id = 2;       // 可选字段

  repeated string emails = 3;  // 重复字段

}



// proto3

syntax = "proto3";

message Example {

  string name = 1;            // 默认都是可选

  int32 id = 2;

  repeated string emails = 3;

}

5. 高级特性

5.1 Oneof

代码语言:protobuf
复制
message SampleMessage {

  oneof test\_oneof {

    string name = 1;

    int32 id = 2;

  }

}

5.2 Map

代码语言:protobuf
复制
message Product {

  map<string, string> properties = 1;

}

5.3 嵌套消息

代码语言:protobuf
复制
message Outer {

  message Inner {

    string text = 1;

  }

  Inner inner = 1;

}

5.4 导入其他文件

代码语言:protobuf
复制
import "other.proto";

5.5 包和命名空间

代码语言:protobuf
复制
package my.package;



// Java 特定选项

option java\_package = "com.example.generated";

option java\_outer\_classname = "ExampleProto";

6. 实际应用示例

6.1 完整的 .proto 文件

代码语言:protobuf
复制
syntax = "proto3";



package tutorial;



option java\_package = "com.example.tutorial";

option java\_outer\_classname = "AddressBookProtos";



message Person {

  string name = 1;

  int32 id = 2;

  string email = 3;



  enum PhoneType {

    MOBILE = 0;

    HOME = 1;

    WORK = 2;

  }



  message PhoneNumber {

    string number = 1;

    PhoneType type = 2;

  }



  repeated PhoneNumber phones = 4;

}



message AddressBook {

  repeated Person people = 1;

}

6.2 Python 使用示例

代码语言:python
复制
import addressbook\_pb2



# 创建消息

person = addressbook\_pb2.Person()

person.id = 1234

person.name = "John Doe"

person.email = "jdoe@example.com"



phone = person.phones.add()

phone.number = "555-4321"

phone.type = addressbook\_pb2.Person.HOME



# 序列化

serialized\_data = person.SerializeToString()



# 反序列化

new\_person = addressbook\_pb2.Person()

new\_person.ParseFromString(serialized\_data)



print(f"Name: {new\_person.name}")

print(f"Email: {new\_person.email}")

6.3 Java 使用示例

代码语言:java
复制
// 创建 Builder

Person person = Person.newBuilder()

    .setId(1234)

    .setName("John Doe")

    .setEmail("jdoe@example.com")

    .addPhones(

        Person.PhoneNumber.newBuilder()

            .setNumber("555-4321")

            .setType(Person.PhoneType.HOME)

            .build())

    .build();



// 序列化

byte[] serializedData = person.toByteArray();



// 反序列化

Person newPerson = Person.parseFrom(serializedData);



System.out.println("Name: " + newPerson.getName());

System.out.println("Email: " + newPerson.getEmail());

7. 编译和使用

7.1 安装编译器

代码语言:bash
复制
# 下载 protoc 编译器

# 或使用包管理器安装

7.2 编译 .proto 文件

代码语言:bash
复制
# 生成 Java 代码

protoc --java\_out=. addressbook.proto



# 生成 Python 代码

protoc --python\_out=. addressbook.proto



# 生成多种语言

protoc --java\_out=. --python\_out=. --cpp\_out=. addressbook.proto

8. 最佳实践

8.1 字段编号

  • 使用 1-15 作为常用字段(占用 1 字节)
  • 16-2047 作为不常用字段
  • 不要随意更改字段编号

8.2 向后兼容

  • 不要删除已使用的字段编号
  • 新字段使用新的编号
  • 已删除的字段可添加 reserved 声明
代码语言:protobuf
复制
message Foo {

  reserved 2, 15, 9 to 11;

  reserved "foo", "bar";

}

8.3 版本管理

  • 在文件名或包名中包含版本信息
  • 使用语义化版本控制

9. 与其他序列化格式对比

| 特性 | Protobuf | JSON | XML |

|------|----------|------|-----|

| 大小 | 小 | 大 | 很大 |

| 速度 | 快 | 慢 | 很慢 |

| 可读性 | 差 | 好 | 好 |

| 类型安全 | 强 | 弱 | 弱 |

| 跨语言 | 优秀 | 优秀 | 优秀 |

10. 使用场景

  • **微服务通信**:gRPC 的默认序列化格式
  • **数据存储**:高效存储结构化数据
  • **配置文件**:强类型的配置定义
  • **API 设计**:定义清晰的接口契约

Protobuf 在现代分布式系统中扮演着重要角色,特别是在性能要求高、需要跨语言协作的场景中表现出色。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Protocol Buffers (Protobuf) 详解
    • 1. 什么是 Protocol Buffers?
    • 2. 核心特性
      • 2.1优点
      • 2.2 缺点
    • 3. 基本语法
      • 3.1 基本消息定义
      • 3.2 字段规则
      • 3.3 数据类型
    • 4. 版本差异
      • proto2 vs proto3
    • 5. 高级特性
      • 5.1 Oneof
      • 5.2 Map
      • 5.3 嵌套消息
      • 5.4 导入其他文件
      • 5.5 包和命名空间
    • 6. 实际应用示例
      • 6.1 完整的 .proto 文件
      • 6.2 Python 使用示例
      • 6.3 Java 使用示例
    • 7. 编译和使用
      • 7.1 安装编译器
      • 7.2 编译 .proto 文件
    • 8. 最佳实践
      • 8.1 字段编号
      • 8.2 向后兼容
      • 8.3 版本管理
    • 9. 与其他序列化格式对比
    • 10. 使用场景
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档