protoBuf-python学习笔记

时间:2022-07-23
本文章向大家介绍protoBuf-python学习笔记,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

protoBuf官方简介

protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法
它可用于(数据)通信协议、数据存储等。

Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法
可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。

你可以定义数据的结构,然后使用特殊生成的源代码
轻松的在各种数据流中使用各种语言进行编写和读取结构数据。
你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。

protobuf通过定义包含类型结构序列化信息的文件(.proto文件),来编译生成不同语言平台的高效序列化程序代码

下载protoBuf编译器

根据不同系统下载不同protoc编译器,在windows下下载windows后缀的 protoc-3.12.0-rc-1-winxxx.zip 解压后得到的目录中,bin目录中的protoc.exe就是编译protoc代码命令

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----         2020/5/5      1:24                bin
d-----         2020/5/5      1:24                include
-a----         2020/5/5      1:24            724 readme.txt

把protoc.exe配置到Path环境变量

编译proto到python代码

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

其中,DST_DIR指定编译的go代码输出路径,SRC_DIR/your.proto指定proto文件,最后一个参数是要编译的proto文件名 最终生成了代码文件xxx_pb2.py

syntax声明

一般在proto文件开头使用syntax声明proto版本,默认是proto2 比如

syntax = "proto3";

导入包

通过import语句导入proto包,比如

import "google/protobuf/struct.proto"

定义message

protobuf中使用关键字message定义结构,并且结构中可以嵌套定义结构,比如

message A {}
message B {
    message C {
    }
}

每个message最终会被解释为一个类,通过该类生成支持protobuf序列化的实例

A = _reflection.GeneratedProtocolMessageType(... ..)
_sym_db.RegisterMessage(A)

B = _reflection.GeneratedProtocolMessageType(... ..)
_sym_db.RegisterMessage(B)
_sym_db.RegisterMessage(B.C)

接下来就可以导入使用

from test_pb2 import *

a = A()
print(a.SerializeToString())

c = B.C()
print(c.SerializeToString())

定义字段

基本定义语法如下,其中type是类型,name是字段名称,num是数据编号 当反序列化时,会把对应数据编号对应的数据填充到对应字段 对于type,如果是message类型,在生成实例时,对应字段会自动构造一个对应message序列化类型的实例,并禁止修改(只能对该属性实例的字段赋值,而不能修改该属性绑定其他实例)

type  name = num
  • 基本类型
    message A {
        string name = 1;
    }
  • message类型
    message B {
        string name = 1;
    }
    message A {
        B b = 1;
    }
  • map
    message A {
        map<string,int> pic = 1;
    }
  • 枚举 枚举类型会被编译为谷歌包的EnumTypeWrapper的实例,每个实例提供对应获取全部枚举量的方法,而枚举常量都是数值类型 比较独特的,枚举枚举中枚举量的数值就是他们编译后代码中常量的初始化数值,第一个枚举量的数据编号必须是0 py中通过该枚举实例的values方法取得全部枚举量的数值表示,通过keys方法取得全部枚举量的字符串表示 枚举类型的成员会被限制只接受int数值
    message A{
      enum Color{
        RED = 0;
        BLACK = 1;
      }
      Color c = 1;
    }
    enum Day{
        ONE = 0;
        TWO = 1;
    }
  • repeated类型(数组) 通过在类型前加上关键字repeated代表其为数组类型,该字段序列化可能出现0次或多次,比如
    message B{}
    message A{
      repeated B bs= 1;
    }
类似的,repeated属性也是在实例化时自动构造空数组,并禁止对属性赋值,只能操作数组往里面增删元素,且元素类型必须符合指定的类型

定义服务

proto支持通过service与rpc关键字分别定义rpc服务和rpc方法,proto默认不会生成rpc代码,需要结合对应的rpc插件(grpc、twirp等)编译才会生成 比如如下代码,定义了一个service,提供一个search的rpc调用方法,接收一个Request类型的参数,返回Response类型的结果

message Request{}
message Response{}
service Search{
    rpc search(Request) returns(Response);
}

结合grpc生成py的rpc代码

需要先安装python相关的grpc模块(下面使用国内镜像)

pip install grpcio-tools -i https://pypi.tuna.tsinghua.edu.cn/simple

然后使用grpc模块结合protobuf生成对应的rpc的server和client

python -m grpc_tools.protoc -I . --python_out=. --grpc_python_out=. test.proto

这时发现本次proto编译比上次多了一个test_py2_grpc.py,包含rpc的内容 里面提供XXXServicer类,具备对应的映射方法抛出异常(提示需要你去重写映射后的处理和返回结果) 然后还有一个add_XXXServicer_to_server方法,第一个参数接收上面XXXService的一个实例对象,第二个参数接收一个grpc.Server的对象,也就是继承XXXService类,重写映射处理方法,实例化一个子类对象,利用提供的add_XXXServicer_to_server,把该子类对象添加到对应的grpc.Server对象,则可以完成添加rpc方法到grpcServer中