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) //反序列化數據
............
}
)