zoukankan      html  css  js  c++  java
  • protobuf数据描述语言

    1.简介

    Protocol Buffers是Google开发的一种数据描述语言,能够将数据进行序列化,可用于数据存储、通信协议等方面。

    可以理解成更快、更简单、更小的JSON或者XML,区别在于Protocol Buffers是二进制格式,而JSON和XML是文本格式。

    相对于XML,Protocol Buffers有如下几个优点:

    1.简洁。

    2.体积小,消息大小只有XML的1/10到1/3。

    3.速度快,解析速度比XML快20~100倍。

    4.使用Protocol Buffers的编译器,可以生成更容易在编程中使用的数据访问代码。

    5.更好的兼容性,Protocol Buffers设计的一个原则就是要能够很好的支持向下或向上兼容。

     

    使用不同的数据描述语言序列化后的字节个数比对:

     

    使用不同的数据描述语言进行序列化以及反序列化的响应时间比对:

     

     

    *数据在网络进行传输时要经历三个阶段: 发送方对数据进行序列化、网络中传输、接收方反序列化。

    将对象序列化成protobuf、xml、json结构时,protobuf所占的字节数量最少、有效数据的比重最大、总数据最少,因此决定了数据在网络进行传输时所耗费的时间最少。

    将对象序列化成protobuf、xml、json结构以及反序列化成对象时,protobuf所耗费的时间最少。

     

    结论:数据使用protobuf序列化格式能够大大提高生产效率(服务的响应时间)。 

     

     

    2.proto文件的语法规则 

     

    字段类型

     

    *目前有v2、v3版本,不同版本的语法稍微有些不同,会额外进行说明,以下是v2版本的语法规则。

    2.1 消息

    1.使用message关键字定义消息,并指定消息的名称(取一个有意义的名字)

    2.指定字段的类型和名称

    3.添加字段的约束

    4.定义字段的编号(从1开始,其中19000~19999被Protocol Buffers作为保留字段)

     

     最基本的message

    message User{
        required int32 id = 1;
        required string username = 2;
        required string password = 3;
        optional string email = 4;
    }

     

    字段约束

    required指定该字段必须赋值。

    optional表示该字段允许为空,可以使用[default]指定默认值,如果没有指定默认值则会使用字段类型的默认值。

    • 对于strings ,默认是一个空string。
    • 对于bytes ,默认是一个空的bytes。
    • 对于bools ,默认是false。
    • 对于数值类型 ,默认是0。
    • 对于枚举,默认是第一个定义的枚举值,必须为0。

    repeated指定字段为集合。

    oneof指定一组字段中必须有一个字段要赋值。

     

    *在一个proto文件中可以同时定义多个message类型,生成代码时根据生成代码的目标语言不同,处理的方式不太一样( 对于Java, 每个proto文件都生成一个类,即一个.java文件,每个message、enum类型都是该类的静态内部类 )

    message User{
        required int32 id = 1;
        //username或email之间必须有一个字段要赋值
        oneof login{
          string username = 3;
          string email = 4;
        }
        required string password = 2;
    }
    
    message Admin{
        required int32 id = 1;
        required string username = 2;
        required string password = 3;
    }

     

    *可以指定字段的类型为其他的message类型。

    message Course{
        required User user = 1;
        required string cour_name = 2; 
    }
    
    message User{
        required int32 id = 1;
        required string username = 2;
        required string password = 3;
        optional string email = 4;
    }

     

    *在proto文件中支持类型的嵌套,即定义的message类型仅作为包含其message类型的字段类型( 此时Course静态内部类中包含User静态内部类 )

    message Course{
        message User{
            required int32 id = 1;
            required string username = 2;
            required string password = 3;
            optional string email = 4;
        }
        required User user = 1;
        required string cour_name = 2; 
    }

     

    *使用extensions关键字预留消息类型的字段编号,通过extend关键字继续定义。

    message User{
        //30~100编号为User类型私有.
        extensions 30 to 100
    }
    
    extend User{
        required int32 id = 1;
        required string username = 2;
        required string password = 3;
        optional string email = 4;
    }

     

    2.2 枚举

    1.使用enum关键字定义枚举,并指定枚举的名称(取一个有意义的名字)

    2.设置枚举可能包含的值并定义编号(从1开始,其中19000~19999被Protocol Buffers作为保留字段)

     

    最基本的枚举:

    enum Course{
          Chinese = 1;
          Mathematics = 2;
          English = 3;  
    }

     

    *可以使用import关键字导入其他proto文件。

    *可以使用option java_package设置生成java类的包名。

    *可以使用option java_outer_classname设置生成java类的类名。

    import "other.proto"
    option java_package = "com.zht.protobuf";
    option java_outer_classname = "UserModel";
    message User{
        required int32 id = 1;
        required string username = 2;
        required string password = 3;
        optional string email = 4;
    }
    

     

     

    3.proto2与proto3的不同

    1.proto文件的第一行必须使用syntax属性指定使用的protobuf版本:proto2、proto3。

    2.移除了 “required” 字段约束。

    3.“optional”字段约束改名为 “singular”。

    4.在 proto2 中, "optional" 约束可以使用 default 指定字段的默认值(不指定也不赋值则跟随系统), 在 proto3 中, 字段的默认值只能根据字段类型由系统决定。

    *字段被设置为默认值时, 该字段不会被序列化, 提高效率。

    5.枚举类型的第一个字段的编号必须为 0 。

     

     

    4.protobuf的使用

     

    1.环境的准备

     

    在github下载对应操作环境的protobuf工具包: https://github.com/google/protobuf/releases

    windows用户选择: protoc-3.5.1-win32.zip

    解压后配置环境变量PATH,使其在上下文能直接搜索 protoc.exe。

     

    2.编写.proto文件

    E:protouser.proto

    内容如下:

    #v3版本需要在proto文件的第一行使用syntax属性指定proto文件使用的语法的版本
    syntax = "proto2"; option java_package = "com.zht.protobuf"; option java_outer_classname = "UserModel"; message User{ required int32 id = 1; required string username = 2; required string password = 3; optional string email = 4; }

     

    3.使用protoc.exe命令生成实体

     

    protoc.exe -I [proto文件所在目录] --java_out  [JAVA类存放目录]  [proto文件绝对路径]

     

     

     

    4.将实体放入工程进行实体的构造和赋值

     

    将实体放入工程:

     

    构造并且赋值:

    public class Main {
    
        public static void main(String[] args) throws InvalidProtocolBufferException {
            //获取构造器并进行赋值
            UserModel.User.Builder builder = UserModel.User.newBuilder();
            builder.setId(1);
            builder.setUsername("zhuanght");
            builder.setPassword("123456");
            builder.setEmail("aiuzht119@163.com");
            
            //获取实体
            UserModel.User user = builder.build();
            
            System.out.println("源数据:
    "+ user.toString());
            System.out.println("序列化后:"+Arrays.toString(user.toByteArray()));
    
            //模拟接收Byte[],反序列化成User实体
            byte[] data =user.toByteArray();
            User u = User.parseFrom(data);
            System.out.println("
    解析:
    " +u.toString());
        }
        
    }

     

    打印结果 :

    源数据:
    id: 1
    username: "zhuanght"
    password: "123456"
    email: "aiuzht119@163.com"
    
    序列化后:[8, 1, 18, 8, 122, 104, 117, 97, 110, 103, 104, 116, 26, 6, 49, 50, 51, 52, 53, 54, 34, 17, 97, 105, 117, 122, 104, 116, 49, 49, 57, 64, 49, 54, 51, 46, 99, 111, 109]
    
    解析:
    id: 1
    username: "zhuanght"
    password: "123456"
    email: "aiuzht119@163.com"
    

      

    5.获取序列化后的字节数组在网络中进行传输

     

     

    5.protobuf实例与json进行转换

     

    导入相关依赖

    <dependency>
        <groupId>com.googlecode.protobuf-java-format</groupId>
        <artifactId>protobuf-java-format</artifactId>
        <version>1.4</version>
    </dependency>

     

    protobuf实例序列化为json格式

    //user为上面例子的UserModel.User消息实例
    String json = JsonFormat.printToString(user)

     

    json序列化为protobuf实例

    //builder为上面例子的UserModel.User.Builder构造器实例
    JsonFormat.merge(json ,builder);
    //此时再使用构建器创建的实例就包含转换后的数据
    builder.build();

     

  • 相关阅读:
    IIS使用URL重写(URL Redirect)实现http跳转到https
    iis10中,安装URL重定向,却提示需要IIS7版本以上
    部署ABO+Angular框架要注意的问题
    idea中写Spring遇到internal error
    用微信小程序连接leancloud数据库注意事项~
    static解析
    Data Science Leetcode 精简版
    专题:二叉搜索树
    239. 滑动窗口最大值/双端队列/单调队列
    【转】关闭firefox火狐浏览器下载完成时自动扫描(49.0.2以后版本)
  • 原文地址:https://www.cnblogs.com/funyoung/p/8645562.html
Copyright © 2011-2022 走看看