protocol buffers


什么是Protocol Buffers

Protocol Buffers (简称 Protobuf)是 Google 开源的一款跨语言,跨平台,扩展性好的序列化工具,相比于 XML 和 JSON 等流行的编码格式,Protobuf 的性能非常高。因此,Protobuf 的编码格式(文件后缀为 .proto)在网络开发中得到了广泛的应用,protoc 作为 Protobuf 的编译器,可以根据 Protobuf 的定义文件 .proto 生成多种语言(如:C++, Java, Go, Python 等)的类型定义文件及编解码操作代码。
其他详情可以参考官方文档

安装

源码安装

官方源码:https://github.com/google/protobuf
可以选择releases获取最新版和选择官方支持的语言版本

安装依赖

如官网所列,protoc 有如下依赖:
autoconf, automake, libtool, curl, make, g++, unzip, gmock
其中 gmock 依赖于 libtool

编译安装:

$ wget https://github.com/protocolbuffers/protobuf/releases/download/v3.7.1/protobuf-all-3.7.1.tar.gz
$ tar xf protobuf-all-3.7.1.tar.gz
$ cd protobuf-all-3.7.1
$ ./configure
$ make
$ make check
$ sudo make install

注:
安装完成之后,会在 /usr/lib 目录下生成前缀为 libprotobuf, libprotobuf-lite, libprotoc 这三类静态和动态库文件。

二进制

支持golang

下载编译器插件

go get  -u github.com/golang/protobuf/protoc-gen-go

会在$GOPATH/bin中生成可执行文件protoc-gen-go,可以将文件移动至$PATH里面的目录下或者将$GOPATH/bin加入$PATH

运行

C++

protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto

$SRC_DIR表示应用程序源代码文件所在目录(如果不写即是当前目录.),DST_DIR表示生成文件的目录,最后指出需要编译的目标proto文件。

Golang

protoc -I=$SRC_DIR --go_out=$DST_DIR $SRC_DIR/addressbook.proto

$SRC_DIR表示应用程序源代码文件所在目录(如果不写即是当前目录.),DST_DIR表示生成文件的目录,最后指出需要编译的目标proto文件。

版本

proto2

示例:

syntax = "proto2";
package hw;
/*
    注释风格支持C语言注释
*/

// 导入其他文件的message
import "hw.import.proto";

// 枚举类型
enum Corpus {
    // 设置保留字段
    reserved 7, 15, 9 to 11, 40 to max; // 保留字段编号
    reserved "FOO", "BAR"; // 保留字段名称
    // 开启别名
    option allow_alias = true;
    UNIVERSAL = 0;
    DEFAULT = 0; // 开启别名可以多个字段使用同一个字段编号
    WEB = 1;
    IMAGES = 2;
    LOCAL = 3;
    NEWS = 4;
    PRODUCTS = 5;
    VIDEO = 6;
}

// 定义消息体
/*
变量值类型与转换为语言后的类型
proto Type  C++ Type    Java Type   Go Type     Python Type[2]
double      double      double      *float64    float
float       float       float       *float32    float
int32       int32       int         *int32      int
int64       int64       long        *int64      int/long[3]
uint32      uint32      int[1]      *uint32     int/long[3]
uint64      uint64      long[1]     *uint64     int/long[3]
sint32      int32       int         *int32      int
sint64      int64       long        *int64      int/long[3]
fixed32     uint32      int[1]      *uint32     int/long[3]
fixed64     uint64      long[1]     *uint64     int/long[3]
sfixed32    int32       int         *int32      int
sfixed64    int64       long        *int64      int/long[3]
bool        bool        boolean     *bool       bool
string      string      String      *string     unicode(Python2)|str(Python3)
bytes       string      ByteString  []byte      bytes
*/
message HelloWorld {
    // 设置保留字段
    reserved 2, 15, 9 to 11; // 保留字段编号
    reserved "foo", "bar"; // 保留字段

    required string query = 1; // 设置字段
    optional int32 page_number = 4 [default = 10]; // 设置字段默认值
    repeated int32 result_per_page = 3 [packed = true]; // 循环字段可以使用packed设置高效编码
    optional Corpus corpus = 5 [default = UNIVERSAL]; // 设置枚举类型
    optional Imported imported = 6; // 设置外部文件message

    // 嵌套message
    message Result {
        optional int32 status_code = 1; // 可重新利用字段编号
    }

    // 扩展字段编号
    extensions 100 to 199;

    // OneOf,字段编号不能与已定义的编号冲突
    oneof test_oneof {
        string name = 7;
        string sex = 8;
    }
}

// 使用其他message内部的message
message Response {
    required HelloWorld.Result result = 1;
}

// 声明扩展
extend HelloWorld {
    optional int32 bar = 126;
}
// 在类型内声明扩展
message ExHelloWorld {
    extend HelloWorld {
        optional int32 bar_ex = 127;
    }
}
// 直接调用扩展
message ExtendHelloWorld {
    optional HelloWorld hello_world = 1;
}

proto3

示例:

优缺点

优点

  • 小巧,采用二进制流,便于传输数据
  • 快速,编码解码比较快
  • 方便,自动生成相应的操作代码,减少了维护代码的成本,支持大部分主流语言,无需关心底层,直接调用函数即可
  • 兼容性好,不必破坏已部署的、依靠“老”数据格式的程序就可以对数据结构进行升级。这样您的程序就可以不必担心因为消息结构的改变而造成的大规模的代码重构或者迁移的问题。因为添加新的消息中的 field 并不会引起已经发布的程序的任何改变。

缺点

  • 可读性差,对机器友好,对人不友好。如果没有.proto文件无法表示数据含义,所以使用场景一般是内部服务的数据传输
  • 描述数据能力差,无法类似xml那样自描述字段相关内容

文章作者: Djaigo
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Djaigo !
评论
  目录