protocol-buffers初使用

2022-09-23  本文已影响0人  WilsonMing

什么是ProtoBuffers

ProtoBuf(Protocol Buffers)是一种跨平台、语言无关、可扩展的序列化结构数据的方法,可用于网络数据交换及存储。一般简称pb
一旦定义了要处理的数据的数据结构之后,就可以利用ProtoBuf的代码生成工具生成相关的代码。只需使用 Protobuf 对数据结构进行一次描述,即可利用各种不同语言(proto3支持C++, Java, Python, Go, Ruby, Objective-C, C#)或从各种不同流中对你的结构化数据轻松读写。

为什么是 ProtoBuffers

ProtoBuf 现在是 Google 用于数据交换和存储的通用语言。谷歌代码树中定义了 48162 种不同的消息类型,包括 12183 个 .proto 文件。它们既用于 RPC 系统,也用于在各种存储系统中持久存储数据。

数据格式 1000条数据 5000条数据
Protobuf 195ms 647ms
Json 515ms 2293ms

序列化空间效率对比:

数据格式 5000条数据
Protobuf 22MB
Json 29MB

优点

proto3支持C++, Java, Python, Go, Ruby, Objective-C, C#。

缺点

ProtoBuf是二进制协议,编码后的数据可读性差,如果没有idl文件,就无法理解二进制数据流,对调试不友好。

如何使用pb

dependencies {
        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.19'
}

plugins {
     ...
    id 'com.google.protobuf' version '0.8.19' apply false
}
apply plugin: 'com.google.protobuf'

android {
    sourceSets {
        main {
            // 定义proto文件目录
            proto {
                srcDir 'src/main/proto'
                include '**/*.proto'
            }
        }
    }
}

dependencies {
    implementation 'com.google.protobuf:protobuf-java:3.17.2'
}

protobuf {
    //配置protoc编译器
    protoc {
      //  不支持 mac m1 arg使用x86_64
        if (osdetector.os == "osx") {
            //区分平台
            artifact = 'com.google.protobuf:protoc:3.17.2:osx-x86_64'
        } else {
            artifact = 'com.google.protobuf:protoc:3.17.2'
        }
    }
    //这里配置生成目录,编译后会在build的目录下生成对应的java文件
    generateProtoTasks {
        all().each { task ->
            task.builtins {
                remove java
            }
            task.builtins {
                java {}
            }
        }
    }
}   

plugins {
    id 'com.google.protobuf'
}

android {
    sourceSets {
        main {
            // 定义proto文件目录
            proto {
                srcDir 'src/main/proto'
                include '**/*.proto'
            }
        }
    }
}

dependencies {
    implementation 'com.google.protobuf:protobuf-java:3.17.2'
}
protobuf {
    //配置protoc编译器
    protoc {
//  不支持 mac m1 arg使用x86_64
        if (osdetector.os == "osx") {
            //区分平台
            artifact = 'com.google.protobuf:protoc:3.17.2:osx-x86_64'
        } else {
            artifact = 'com.google.protobuf:protoc:3.17.2'
        }
    }
    //这里配置生成目录,编译后会在build的目录下生成对应的java文件
    generateProtoTasks {
        all().each { task ->
            task.builtins {
                remove java
            }
            task.builtins {
                java {}
            }
        }
    }
}
//pb版本
syntax = "proto3";
//存放位置
option java_package = "com.mysiga.netsocket";
//输出类名
option java_outer_classname = "Person";
//引入类
import "Adress.proto";
//定义类
message _Person{
//  定义字段为name的字段,数据为字符串
  string name = 1;
  int32 id = 2;
  string email = 3;
  bool isCheck = 4;
//  枚举
  enum _PhoneType{
    MOBILE=0;
    HOME=1;
    WORK=2;
  }
//  内部类
  message _PhoneNumber{
    string number=1;
    _PhoneType type=2;
  }
  string card=5;
//  集合
  repeated _PhoneNumber phone=6;
  _Adress adress=7;
}

Adress.proto

syntax="proto3";
option java_package="com.mysiga.netsocket";
option java_outer_classname="Adress";
message _Adress{
  string address=1;
}
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val phoneNumber=Person._Person._PhoneNumber.newBuilder().setNumber("1883883")
        val personBuild=Person._Person.newBuilder().setCard("汽车")
.setEmail("121431@qq.com").setIsCheck(true).addPhone(phoneNumber).setName("Wilson")
        val person=personBuild.build()
        Log.i("Wilson","name ${person}")
//        序列化
        val bytes=person.toByteArray()
//        反序列化
        try {
            val person1=Person._Person.parseFrom(bytes)
            Log.i("Wilson","name:${person1}")
            Log.i("Wilson","card:${person1.card}")
        } catch (e: InvalidProtocolBufferException) {
            e.printStackTrace()
        }
    }
}

总结

对于数据交互频繁且数据量大,建议使用pb,对于游戏或在线教育白板业务场景下基本都是用pb。只是可读性差点。如果数据量不大可用Json可读性高。以上就是简单实用。复杂实用还要深研究下官方文档了。

扩展资料

.proto Type Notes C++ Type Java Type Python Type[2] Go Type Ruby Type C# Type PHP Type
double double double float float64 Float double float
float float float float float32 Float float float
int32 使用变长编码,对于负值的效率很低,如果你的域有可能有负值,请使用sint64替代 int32 int int int32 Fixnum 或者 Bignum(根据需要) int integer
uint32 使用变长编码 uint32 int int/long uint32 Fixnum 或者 Bignum(根据需要) uint integer
uint64 使用变长编码 uint64 long int/long uint64 Bignum ulong integer/string
sint32 使用变长编码,这些编码在负值时比int32高效的多 int32 int int int32 Fixnum 或者 Bignum(根据需要) int integer
sint64 使用变长编码,有符号的整型值。编码时比通常的int64高效。 int64 long int/long int64 Bignum long integer/string
fixed32 总是4个字节,如果数值总是比总是比228大的话,这个类型会比uint32高效。 uint32 int int uint32 Fixnum 或者 Bignum(根据需要) uint integer
fixed64 总是8个字节,如果数值总是比总是比256大的话,这个类型会比uint64高效。 uint64 long int/long uint64 Bignum ulong integer/string
sfixed32 总是4个字节 int32 int int int32 Fixnum 或者 Bignum(根据需要) int integer
sfixed64 总是8个字节 int64 long int/long int64 Bignum long integer/string
bool bool boolean bool bool TrueClass/FalseClass bool boolean
string 一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。 string String str/unicode string String (UTF-8) string string
bytes 可能包含任意顺序的字节数据。 string ByteString str []byte String (ASCII-8BIT) ByteString string
上一篇下一篇

猜你喜欢

热点阅读