Protocol buffers基础及okhttp应用

2,507 阅读4分钟

一、基础知识

1.1 简介

Protocol buffers是一种与语言无关、与平台无关的、可扩展的序列化结构数据,存放数据格式定义的文件后缀为 .proto。
序列化结构数据的方式有XML、Json等,相比XML、Json,Protocol buffers体积更小、解析更快。

1.2 Protocol buffers语法

Protocol buffers定义了一套语法来表示数据:pb语法; 列举几个比较常用的:

// 第一行表示语法格式
syntax = "proto2";

package com.bc.model.proto;
option optimize_for = LITE_RUNTIME; //减少Java端生成的代码大小

// message表示消息对象
message User {
	// option表示可选
   optional string name = 1;
   optional int64 age = 2;
}

1.3 Protocol buffers数据定义示例

例如对于一个User中包含Name及Age:
(1)用xml表示如下:

<?xml version="1.0" encoding="utf-8"?>
<User>
	<Name value = "jack"/>
	<Age value = 18/>
</User>

(2)用json表示如下:

{
	"User": {
		"Name" : "Jack",
		"Age" : 18
	}
}

(3)用Protocol buffers表示时,首先定义语法格式如下:

syntax = "proto2";

package com.bc.model.proto;
option optimize_for = LITE_RUNTIME; //减少Java端生成的代码大小

message User {
	optional string name = 1;
	optional int64 age = 2;
}

然后根据编译器生成的平台代码来设置User的值:

UserModelProto.User.Builder builder = UserModelProto.User.Builder.newBuilder();
UserModelProto.User user = builder.setName("jack").setAge(18).build();
// 各个角色互相传递的是byte数组
byte[] byteArray = user.toByteArray();

1.4 为什么性能好

(1)Protocol Buffer的Tag - Length - Value 、Tag - Value存储方式,使数据存储更紧凑,也减少了分隔符的使用;
(2)Protocol Buffer对于数据字段值的独特编码方式(Varint & Zigzag等) 减少了字段值占用字节数;
(3)Protocol Buffer中的optional字段如果未设置值,则不进行编码;

二、Protocol buffers编译器

Protocol buffers编译器用于在命令行输入相应命令,根据protocol buffer文件生成对应的平台(java、c++等)代码或描述文件等;

2.1 安装步骤

  1. 下载pb:developers.google.com/protocol-bu…
  2. 下载后的文件中install.txt中说明步骤进行安装:
 1. `cd' to the directory containing the package's source code and type
    `./configure' to configure the package for your system.  If you're
    using `csh' on an old version of System V, you might need to type
    `sh ./configure' instead to prevent `csh' from trying to execute
    `configure' itself.

    Running `configure' takes awhile.  While running, it prints some
    messages telling which features it is checking for.

 2. Type `make' to compile the package.

 3. Optionally, type `make check' to run any self-tests that come with
    the package.

 4. Type `make install' to install the programs and any data files and
    documentation.

 5. You can remove the program binaries and object files from the
    source code directory by typing `make clean'.  To also remove the
    files that `configure' created (so you can compile the package for
    a different kind of computer), type `make distclean'.  There is
    also a `make maintainer-clean' target, but that is intended mainly
    for the package's developers.  If you use it, you may have to get
    all sorts of other programs in order to regenerate files that came
    with the distribution.
  1. 安装成功后,命令行输入protoc --version可查看版本号,证明安装成功;
>protoc --version
#结果:
>libprotoc 2.5.0

2.2 生成平台代码

通过Protocol Buffer 编译器编译 .proto 文件生成目标代码,安装protocol buffer编译器后,在shell中输入如下命令:

# 用法如下:
# -I=proto文件所在目录
# --java_out 需要生成的java目标代码文件夹;
>protoc -I=/Users/bc/proto --java_out=/Users/bc/proto /Users/bc/proto/user_proto.proto

2.3 卸载步骤

如果需要卸载protoc编译器,按如下步骤操作,在shell中输入如下命令:

# 查找protoc位置
>which protoc
/usr/local/bin/protoc
# 卸载protoc
>rm /usr/local/bin/protoc

三、Java中的Protocol buffers

在用Protocol buffers编译器生成Java平台代码后,可将代码复制到工程中,按如下步骤使用:

3.1 添加依赖

 implementation 'com.google.protobuf:protobuf-java:2.7.0'

3.2 创建Protocol buffers数据

UserModelProto.User.Builder builder = UserModelProto.User.Builder.newBuilder();
UserModelProto.User user = builder.setName("jack").setAge(18).build();
// 各个角色互相传递的是byte数组
byte[] byteArray = user.toByteArray();

3.3 解析Protocol buffers

// 假设是其他角色传送过来的byte数组
byte[] byteArray = getByteArray();
UserModelProto.User user = UserModelProto.User.parseFrom(byteArray);

四、Protocol buffers与Okhttp

4.1 发送请求

// 1. 创建user
val builder = UserModelProto.User.Builder.newBuilder();
val user = builder.setName("jack").setAge(18).build();
// 2.创建RequestBody **
val requestBody = RequestBody.create("application/x-protobuf", user.toByteArray())
// 3.构建okHttpClient
val okHttpClient = OkHttpClient.Builder()
    .connectionPool(ConnectionPool(2, 35, TimeUnit.SECONDS))
    .connectTimeout(10, TimeUnit.SECONDS)
    .readTimeout(15, TimeUnit.SECONDS)
    .writeTimeout(15, TimeUnit.SECONDS)
    .build()
// 4.构建request,并post(requestBody) **
val request = Request.Builder()
    .url("https://www.baidu.com").addHeader("COOKIE", "cookie").post(requestBody).build()

// 5.发送请求
okHttpClient.newCall(request).enqueue(object : Callback {
    override fun onFailure(call: Call, e: IOException) {
        TODO("Not yet implemented")
    }

    override fun onResponse(call: Call, response: Response) {
        TODO("Not yet implemented")
    }
})

4.2 解析请求结果

解析请求结果的代码在onResponse()中:

okHttpClient.newCall(request).enqueue(object : Callback {
	override fun onResponse(call: Call, response: Response) {
        ResponseBody responseBody = response.body();
        if (responseBody == null) {
        	return null;
    	}
   	 	BufferedSource bufferedSource = responseBody.source();
    	UserModelProto.User user = null;
   		if (bufferedSource != null) {
        	while (!bufferedSource.exhausted()) {
        		user = UserModelProto.User.parseDelimitedFrom(bufferedSource.inputStream());
        		if (protoResponse == null) {
        			break;
        		}
    		}
    	}
    }
    
    override fun onFailure(call: Call, e: IOException) {
        TODO("Not yet implemented")
    }
})

五、Charles抓包pb数据

5.1 生成pb描述文件

# 用法如下:
# -I=proto文件所在目录
# --descriptor_set_out 需要生成描述文件的路径;
>protoc -I=/Users/bc/proto --descriptor_set_out=response_proto.desc response_proto.proto

5.2 设置pb描述文件

点击Charles内的View-Protobuf Settings...;然后点击add,将proto.desc文件add进去,添加后如下图所示: 在这里插入图片描述

5.3 选择Viewer Mappings

点击Charles内的View-Viewer Mappings...;然后选中Enable Viewer Mapping,然后add需要映射的请求: 在这里插入图片描述 至此设置完成,后续该接口的请求及返回结果中的protocol buffer数据即可展示出来。

The End

欢迎关注我,一起解锁更多技能:BC的主页~~💐💐💐 个人信息汇总.png

官方文档:developers.google.com/protocol-bu…
protobuf github:github.com/protocolbuf…