ProtoBuf应用

1,153 阅读3分钟

Protobuf 的使用

1.创建一个.proto文件,定义好消息体

idea中Protobuf Support插件可以支持.proto文件高亮显示。 (我的.proto文件由协议制定方提供)

2.将.proto文件转成Java类(我用的是其中2.2提供的方法)

2.1一般的做法,是执行protoc命令,依次将.proto文件转成Java类:

protoc.exe -I=d:/tmp --java_out=d:/tmp d:/tmp/monitor_data.proto

  不过gRPC官方推荐了一种更优雅的使用姿势,可以通过maven轻松搞定

2.2 pom.xml文件配置

<properties>
    <grpc.version>1.6.1</grpc.version>
    <protobuf.version>3.3.0</protobuf.version> 
</properties>
  <dependencies>
         <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty</artifactId>
            <version>${grpc.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <version>${grpc.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>${grpc.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>${protobuf.version}</version>
        </dependency>
</dependencies>
<build>
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.5.0.Final</version>
            </extension>
        </extensions>
        <plugins>
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.5.0</version>
                <configuration>
                    <protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact>
                    <pluginId>grpc-java</pluginId>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>            
        </plugins>
    </build>

3.编译生成Java类

使用maven的编译命令,即可在target中看到根据.proto文件生成的Java类。

注意:

  • 需要根据实际生成java文件的路径更改.proto文件上方的package包路径;
  • 若生成的java文件不可用,考虑是不是java文件过大,超过idea设置的默认值,调整该参数需要找到bin路径下的idea.properties文件,更改idea.max.intellisense.filesize参数;
  • 编译找不到.proto文件路径时,在.proto文件所在的文件夹上右键,设置目录为源文件根目录,或将.proto文件放到编译路径下。

protobuf优点

1、性能好/效率高

  • 时间开销:XML 格式化(序列化)的开销还好;但是 XML 解析(反序列化)的开销就不敢恭维了。 但是 protobuf 在这个方面就进行了优化。可以使序列化和反序列化的时间开销都减短。
  • 空间开销:也减少了很多

2、有代码生成机制

比如写一个类似结构体的内容 message testA { required int32 m_testA = 1; } 像写一个这样的结构,protobuf 可以自动生成它的 .h 文件和点 .cpp 文件。

protobuf 将对结构体 testA 的操作会封装成一个类。

3、支持向后兼容和向前兼容

当客户端和服务器同时使用一个协议时,客户端在协议中增加一个字节,并不会影响客户端的使用。

4、支持多种编程语言

在Google官方发布的源代码中包含了

  • C++
  • C#
  • Dart
  • Go
  • Java
  • Kotlin
  • Python

protobuf缺点

1、二进制格式导致可读性差

为了提高性能,protobuf 采用了二进制格式进行编码。这直接导致了可读性差,影响开发测试时候的效率。当然,在一般情况下,protobuf 非常可靠,并不会出现太大的问题。

2、缺乏自描述

一般来说,XML 是自描述的,而 protobuf 格式则不是。它是一段二进制格式的协议内容,并且不配合写好的结构体是看不出来什么作用的。

3、通用性差

protobuf 虽然支持了大量语言的序列化和反序列化,但仍然并不是一个跨平台和语言的传输标准。在多平台消息传递中,对其他项目的兼容性并不是很好,需要做相应的适配改造工作。相比 json 和 XML,通用性还是没那么好。

protobuf高效的秘密在于它的编码格式,它采用了 TLV(tag-length-value) 编码格式。每个字段都有唯一的 tag 值,它是字段的唯一标识。length 表示 value 数据的长度,length 不是必须的,对于固定长度的 value,是没有 length 的。value 是数据本身的内容。

对于 tag 值,它有 field_number 和 wire_type 两部分组成。field_number 就是在前面的 message 中我们给每个字段的编号,wire_type 表示类型,是固定长度还是变长的。 wire_type 当前有0到5一共6个值,所以用3个 bit 就可以表示这6个值。tag 结构如下图。

wire_type 值如下表, 其中3和4已经废弃,我们只需要关心剩下的4种。对于 Varint 编码数据,不需要存储字节长度 length。这种情况下,TLV 编码格式退化成 TV 编码。对于64-bit和32-bit也不需要 length,因为type值已经表明了长度是8字节还是4字节。