protocol buffer基本科普

2019-10-09 15:10:11 浏览数 (1)

pb是谷歌退出的序列化数据传输格式,它以多平台支持,高压缩传输更加快速著称

1 为啥支持多平台

pb有一套自己的语法定义数据格式,根据特性的语法形式定义数据,个人可以根据需要自定义DSL进行格式转换各个平台的语言代码,当然了这样的工作量是巨大的,Google为我们提供基于多种语言的转换支持,如

2 为啥能够传输更加快速

对于模型转化的数据pb最终将数据进行了特定的byte编码,相对于xml与json来说将不必要传输的格式定义等数据给去除掉了。通信的两端则通过pb定义出的数据结构转换出的平台代码完成数据编码与解码

3 pb的缺点

pb虽然数据传输量小,但是传输数据不够直观,接收方需要反序列化才可看到数据,在开发中不利于数据的纠错

使用入门

pb是根据.proto文件定义的数据结构进行平台代码转换,一次我们需先创建以文件。在pb数据结构是以message作为一个基本的数据集合体,同时定义出针对平台兼容的数据转换类型表

代码语言:javascript复制
.proto Type  Notes  C   Type  Java Type  Python Type[2]  Go Type  Ruby Type  C# Type  PHP Type  Dart Type
double    double  double  float  float64  Float  double  float  double
float    float  float  float  float32  Float  float  float  double
int32  Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead.  int32  int  int  int32  Fixnum or Bignum (as required)  int  integer  int
int64  Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead.  int64  long  int/long[3]  int64  Bignum  long  integer/string[5]  Int64
uint32  Uses variable-length encoding.  uint32  int[1]  int/long[3]  uint32  Fixnum or Bignum (as required)  uint  integer  int
uint64  Uses variable-length encoding.  uint64  long[1]  int/long[3]  uint64  Bignum  ulong  integer/string[5]  Int64
sint32  Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s.  int32  int  int  int32  Fixnum or Bignum (as required)  int  integer  int
sint64  Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s.  int64  long  int/long[3]  int64  Bignum  long  integer/string[5]  Int64
fixed32  Always four bytes. More efficient than uint32 if values are often greater than 228.  uint32  int[1]  int/long[3]  uint32  Fixnum or Bignum (as required)  uint  integer  int
fixed64  Always eight bytes. More efficient than uint64 if values are often greater than 256.  uint64  long[1]  int/long[3]  uint64  Bignum  ulong  integer/string[5]  Int64
sfixed32  Always four bytes.  int32  int  int  int32  Fixnum or Bignum (as required)  int  integer  int
sfixed64  Always eight bytes.  int64  long  int/long[3]  int64  Bignum  long  integer/string[5]  Int64
bool    bool  boolean  bool  bool  TrueClass/FalseClass  bool  boolean  bool
string  A string must always contain UTF-8 encoded or 7-bit ASCII text, and cannot be longer than 232.  string  String  str/unicode[4]  string  String (UTF-8)  string  string  String
bytes  May contain any arbitrary sequence of bytes no longer than 232.  string  ByteString  str  []byte  String (ASCII-8BIT)  ByteString  string

下面我们自定义一个看看看如何

代码语言:javascript复制
syntax = "proto3";
option java_package = "app.api";

message Menu{
 int32 id = 1;
 string name = 2;
 int32 status = 3;
 int32 parent = 4;
 string link = 5;
}
message MainMenu{
 int32 id = 1;
 string name = 2;
 int32 status = 3;
 int32 parent = 4;
 string link = 5;
 repeated Menu subs = 6;
}

message MenuEntity{
repeated MainMenu menus = 1;
}

上栗中出现了几个关键点

syntax = "proto3";代表的是对应的pb版本

message 类型与struct和class

repeated代表编译出来是个数组或者list

我们看看怎么编译

代码语言:javascript复制
 protoc --proto_path=./ --java_out=./ *.proto 

proto_path 指定的为pb定义文件的位置

java_out 指代的是编译出的语言此处为java

*.proto 编译那个pb文件,我们此处用的通配符

使用

将编译出的Java代码拷贝项目中即可按照Java方式调用

1 序列化

代码语言:javascript复制
  mutableListOf<MenuOuterClass.MainMenu.Builder>()
        categories.forEach {
            var mainMenu = MenuOuterClass.MainMenu.newBuilder()
            mainMenu.id = it.id
            mainMenu.name = it.name
            mainMenu.status = it.status
            mainMenu.parent = it.parent
            mainMenu.link = it.link
            it.subs.forEach { menu ->
                var subMenu = MenuOuterClass.Menu.newBuilder()
                subMenu.id = menu.id
                if (!menu.name.isNullOrBlank()) {
                    subMenu.name = menu.name
                }
                subMenu.status = menu.status
                subMenu.parent = menu.parent
                if (!menu.link.isNullOrBlank()) {

                    subMenu.link = menu.link
                }
                mainMenu.addSubs(subMenu)
            }
            menus.addMenus(mainMenu)
        }

Kotlin兼容Java,我们按照Kotlin代码来写

模版类似 MenuOuterClass.Menu.newBuilder()找到对应的build一个个属性赋值即即可,最后使用menus.build().toByteString()转化为byte对应的魔种结构

2数据传输

代码语言:javascript复制
        response.contentType = "application/x-protobuf"
        menus.build().writeTo(response.outputStream)
        response.flushBuffer()

3 反序列化

通过接收到到流文件进行反序列化(此处我们的是bytestring)

代码语言:javascript复制
      val decodeEntity =  MenuOuterClass.MenuEntity.parseFrom(byteString)

至此,我们的就可按照对应的class进行业务操作…

公众号了解更多公众号了解更多

0 人点赞