protobuf初探 - golang
认识protobuf
官网:https://developers.google.com/protocol-buffers
protobuf是google 的一种二进制数据交换的格式,类似于 json, xml等也是一种数据格式,是一个语言无关、平台无关的数据序列化工具。简单来说,如果客户端和服务端使用的是不同的语言,那么在服务端定义一个数据结构,通过protobuf转化为字节流,再传送到客户端解码,就可以得到对应的数据结构。
在一些场景下,数据需要在不同的平台,不同的程序中进行传输和使用,例如某个消息是用Java程序编写的的,而另一个程序是用golang写的,当前者产生一个消息数据时,需要在不同的语言编写的不同的程序中进行操作,我们常用的就有json和xml,但
protobuf序列化和反序列的性能都是比较高的,protobuf序列化后的数据体积更小”。
安装 protobuf 编译插件
默认已经安装go环境和brew
- protoc的安装:
命令行执行:
brew install protobuf@3.7
安装完成之后执行:protoc --version 查看是否安装成功以及版本号
protoc --version
如下图显示内容,即为安装成功。
- protoc-gen-go插件的安装(将protobuf的的代码转换成go语言代码的一个插件):
命令行执行
go get github.com/golang/protobuf/protoc-gen-go@v1.3.2
- protoc-gen-micro插件的安装:
Go Micro默认使用protobuf作为通信协议的定义,故需要安装protoc-gen-micro来生成服务的接口代码,这样省去了很多重复的编码工作,同时也保证了代码的准确性。protoc-gen-micro依赖于protoc和protoc-gen-go
命令行执行
go get github.com/micro/protoc-gen-micro@v1.0.0
一个简单的例子-protobuf的使用
目录结构:
定义.proto文件
//.proto文件的第一行(syntax = "proto3";)指定了使用proto3语法。如果省略protocol buffer编译器默认使用proto2语法。他必须是文件中非空非注释行的第一行
syntax = "proto3”;
package proto;
import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto";
//message是protobuf语法中的一个关键字,相当于golang编程语言中的结构体struct,相当于C++中的类。
message SendMessage {
MessageMeta meta = 1;
string Body = 2;
}
message MessageMeta {
google.protobuf.Duration ttr = 1;
google.protobuf.Timestamp timestamp = 2;
string routingKey = 3;
map<string, string> header = 4;
}
编译
进入到main.go所在目录下,打开Terminal执行命令:
protoc -I=proto --go_out=./proto message.proto
将会生成 message.pb.go 文件。message.pb.go文件会自动放入proto文件夹(对应上面package)中
在golang代码中使用protobuf中定义的内容
package main
import (
"fmt"
stProto "./examples/proto"
"github.com/golang/protobuf/proto"
"github.com/micro/go-micro/broker"
"github.com/sirupsen/logrus"
}
func main() {
.........初始化
m := &stProto.SendMessage{
Meta: &stProto.MessageMeta{
Ttr: ptypes.DurationProto(10 * time.Minute),
Timestamp: ptypes.TimestampNow(),
RoutingKey: "micro.email.send",
Header: map[string]string{},
},
Body: *proto.String("test send message by protobuf"),
}
encoded, err := proto.Marshal(m)
if err != nil {
fmt.Printf("Encode to protobuf data error: %v", err)
}
...........
//初始化pb结构体对象,并读取到pb结构体中
msg := &stProto.SendMessage{}
pbErr := proto.Unmarshal(encoded, msg) //反序列化数据
............
}
)