Skip to content

Protocol buffers 协议测试

Protocol buffers are a language-neutral, platform-neutral extensible mechanism for serializing structured data


Protocol Buffers

Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages.
Protocol buffers 是 Google 用于序列化结构化数据的语言中立、平台中立、可扩展机制——想想 XML,但更小、更快、更简单。您只需定义一次数据的结构化方式,然后就可以使用特殊生成的源代码轻松地将结构化数据写入和读取各种数据流,并使用各种语言。


PB 协议的应用 - Dubbo

Dubbo 提供了从服务定义、服务发现、服务通信到流量管控等几乎所有的服务治理能力,并且尝试从使用上对用户屏蔽底层细节,以提供更好的易用性。 定义服务在 Dubbo 中非常简单与直观,可以选择使用与某种语言绑定的方式(如 Java 中可直接定义 Interface),也可以使用 Protobuf IDL 语言中立的方式。无论选择哪种方式,站在服务消费方的视角,都可以通过 Dubbo 提供的透明代理直接编码。


PB 协议的应用 - gRPC

gRPC can use protocol buffers as both its Interface Definition Language (IDL) and as its underlying message interchange format


PB 协议示例

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;
}
Person john = Person.newBuilder()
    .setId(1234)
    .setName("John Doe")
    .setEmail("jdoe@example.com")
    .build();
output = new FileOutputStream(args[0]);
john.writeTo(output);

PB 协议优点

  • 紧凑的数据存储
  • 快速解析
  • 许多编程语言的可用性
  • 通过自动生成的类优化功能

使用流程


pb 使用流程总结

  • 定义消息 Message
  • 编译消息到各个语言代码 Protocol Compiler
  • 在各个语言中构建 Protobuf Runtime
  • 在项目中应用 序列化 反序列化 网络传输等

PB 协议消息


Proto 文件定义

message Person {
  optional string name = 1;
  optional int32 id = 2;
  optional string email = 3;
}

PB 主要定义语法

  • 原始类型: integers, booleans, and floats
  • 消息类型: message
  • 字段规则: required optional repeated

更复杂的消息体定义

syntax = "proto2";

package tutorial;

message Person {
  optional string name = 1;
  optional int32 id = 2;
  optional string email = 3;

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

  message PhoneNumber {
    optional string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phones = 4;
}

message AddressBook {
  repeated Person people = 1;
}

PB 协议编译


编译器下载

  • protoc-21.5-linux-x86_64.zip
  • protoc-21.5-osx-universal_binary.zip
  • protoc-21.5-win64.zip
protoc-$VERSION-$$PLATFORM.zip

编译器命令行用法

protoc
Usage: ./protoc-21.5-osx-aarch_64/bin/protoc [OPTION] PROTO_FILES

protoc --python_out=$DST_DIR demo.proto
protoc --java_out=$DST_DIR demo.proto

PB 安装 Runtime 依赖

Language Source
Java java
Python python

在 Python 中使用 PB


编译 Python 代码

protoc --python_out=$DST_DIR $SRC_DIR/demo.proto

安装依赖

pip install protobuf

Python 测试代码

import demo_pb2


def test_pb():
    person = demo_pb2.Person()
    person.id = 1234
    person.name = "John Doe"
    person.email = "jdoe@example.com"
    phone = person.phones.add()
    phone.number = "555-4321"
    phone.type = demo_pb2.Person.HOME

    raw = person.SerializeToString()
    print(raw)

    person2 = demo_pb2.Person()
    person2.ParseFromString(b'\n\x08John Doe\x10\xd2\t\x1a\x10jdoe@example.com"\x0c\n\x08555-4321\x10\x01')
    print(person2)
    assert person == person2
    assert person.id == person2.id

在 Java 中使用 PB


编译 Java 代码

protoc --java_out=$DST_DIR $SRC_DIR/demo.proto

安装 Runtime 依赖

<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-java</artifactId>
  <version>3.21.4</version>
</dependency>

<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-java-util</artifactId>
  <version>3.21.4</version>
</dependency>

Java 测试代码

```java{data-line-numbers="9-25"} import com.google.protobuf.InvalidProtocolBufferException; import org.junit.jupiter.api.Test; import tutorial.Demo; import tutorial.Demo.*;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class PBDemoTest { @Test void pbDemo() throws InvalidProtocolBufferException { Person john = Person.newBuilder() .setId(1234) .setName("John Doe") .setEmail("jdoe@example.com") .addPhones( Person.PhoneNumber.newBuilder() .setNumber("555-4321") .setType(Person.PhoneType.HOME) ).build();

    byte[] raw = john.toByteArray();
    Person john2 = Person.parseFrom(raw);
    assertEquals(john2.getId(), 1234);
    assertEquals(john, john2);
}

} ```


Q&A