0. 背景
当前流行微服务框架,gRPC和Protocol Buffers 是 Go 的微服务框架常用的框架。
1. Protocol Buffers 介绍
Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
总结下特点就是:
- 它是一种序列化格式,和 JSON,XML 类似。
- 它是二进制的,压缩比例高,短小。
- 序列化处理速度很快
- 非明文传输
- 它通过一种 proto 语法描述格式,可以通过工具生成多种语言代码
- 支持多种开发语言,Java,Go,Python,JS等
Github 地址:https://github.com/golang/protobuf
Protocol Buffers 通常用于 RPC (远程过程调用)过程中,比如微服务间通讯。
2. 开始之前
在开始之前,我们需要先安装和配置开发环境。
分两个步骤:
- 安装 protoc 工具
- 安装 protoc-gen-go
2.1 安装 protoc 工具
在下面这个网址里找到适合你系统的安装包。
https://github.com/protocolbuffers/protobuf/releases
我的机器是mac ,找到 protoc-3.11.4-osx-x86_64.zip 并下载。解压到文件后,修改环境变量。
解压后的文件里有 bin/protoc ,这个 protoc 命令用于编译和生成代码,后面会用到。
建议将这个文件位置放入到环境变量,以方便使用。比如在 修改 .bash_profile 文件,示例:
# PB 工具
export PB_PATH=/Users/zhangyunfei/chengxu/protoc-3.11.4-osx-x86_64
export PATH=$PATH:$PB_PATH/bin
2.2 安装 protoc-gen-go
protoc-gen-go 是 生成 Go 代码的 protocolbuffers 编译器。可以理解为一个编译器插件,配合 protoc 来使用。
在命令行中执行:
go get -u github.com/golang/protobuf/protoc-gen-go
这个工具用于生成 基于 Protocol Buffers 的代码。
3.开始使用
3.1 概述
使用步骤拆解:
- (1) 定义.proto文件,它用来描述,定义传输过程中的数据包。
- (2) 编译.proto文件,生成代码。用来将描述文件编译成指定平台的代码(比如生成GO源代码文件)。
- (3) 获取特定平台的类库/包,用来在特定平台编码,解码等。
下面分别描述这几个步骤。
3.2 定义.proto文件
创建一个 model.proto 文件,它用来描述 数据包的内容,实体对象的字段等。
示例:
syntax = "proto2";
package example;
enum FOO { X = 17; };
message Test {
required string label = 1;
optional int32 type = 2 [default=77];
repeated int64 reps = 3;
}
3.3 编译.proto文件
使用 protoc 生成 Go 源代码文件。
protoc --go_out=paths=source_relative:. model.proto
完成后,将生成的 Go 源代码文件放入项目中。
3.4 导入包和使用
导入包
import (
"fmt"
"github.com/golang/protobuf/proto"
)
序列化
- 使用 proto.Marshal 来将 一个Go Struct 序列化成字节。-
- 字节可以通过HTTP, Socket等网络传输。
- 使用 proto.Unmarshal 来将 字节反序列化成对象。
package main
import (
"fmt"
"github.com/golang/protobuf/proto"
example "gopbdemo/pb"
"log"
)
func main() {
// 一个实体
obj := &example.Test{
Label: proto.String("hello"),
Type: proto.Int32(17),
Reps: []int64{1, 2, 3},
}
// 序列化成字节
data, err := proto.Marshal(obj)
if err != nil {
log.Fatal("序列化时发生错误: ", err)
}
fmt.Println("完成序列化,长度=", len(data))
newObj := example.Test{}
err = proto.Unmarshal(data, &newObj)
if err != nil {
log.Fatal("反序列化时发生错误: ", err)
}
fmt.Println("结果:", newObj.GetLabel(),newObj.GetType(),newObj.GetReps())
}
网友评论