protobuf和json/xml的區別
Protocol Buffer 和 XML、JSON一樣都是結構資料序列化的工具,但它們的資料格式有比較大的區別:
首先,Protocol Buffer 序列化之後得到的資料不是可讀的字串,而是二進位制流
其次,XML 和 JSON 格式的資料資訊都包含在了序列化之後的資料中,不需要任何其它資訊就能還原序列化之後的資料;但使用 Protocol Buffer 需要事先定義資料的格式(.proto 協議檔案),還原一個序列化之後的資料需要使用到這個定義好的資料格式
最後,在傳輸資料量較大的需求場景下,Protocol Buffer 比 XML、JSON 更小(3到10倍)、更快(20到100倍)、使用 & 維護更簡單;而且 Protocol Buffer 可以跨平臺、跨語音使用。
protobuf使用過程
1.通過 Protocol Buffer 語法描述需要儲存的資料結構,就是我們編寫的.proto檔案
2.過 Protocol Buffer 編譯器編譯 .proto 檔案。將 .proto 檔案 轉換成對應平臺(python、C++、Java)的程式碼檔案
protoc -I=$SRC_DIR --xxx_out=$DST_DIR $SRC_DIR/addressbook.proto
# 引數說明
# 1. $SRC_DIR:指定需要編譯的.proto檔案目錄 (如沒有提供則使用當前目錄)
# 2. --xxx_out:xxx根據需要生成程式碼的型別進行設定
"""
對於 Java ,xxx = java ,即 -- java_out
對於 C++ ,xxx = cpp ,即 --cpp_out
"""
# 3. $DST_DIR :編譯後程式碼生成的目錄 (通常設定與$SRC_DIR相同)
# 4. 最後的路徑引數:需要編譯的.proto 檔案的具體路徑
# 編譯通過後,Protoco Buffer會根據不同平臺生成對應的程式碼檔案
go使用protobuf
1.下載protobuf的編譯器protoc,github.com/protocolbuffers/protobu...,根據不同系統安裝對應版本,然後把bin目錄寫到環境變數中,執行protoc –version成功說明安裝成功
>libprotoc 3.17.1
2.獲取protobuf的編譯器外掛protoc-gen-go,其他語言使用其他外掛
這個倉庫官方準備廢棄,使用新
go get -u github.com/golang/protobuf/protoc-gen-go
3.編寫proto檔案,例如hello.proto
syntax = "proto3";
package proto;
option go_package ="./proto";
service Greeter {
rpc Hello(HelloRequest) returns (HelloResponse) {}
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string greeting = 1;
}
4.編譯.proto檔案,發現生成greeter.pb.go檔案
protoc --go_out=. proto/greeter.proto
protoc編譯器原理
protoc編譯器是通過外掛機制實現對不同語言的支援,比如protoc命令出現--xxx_out
格式的引數,那麼protoc將首先查詢是否有內建的xxx外掛,如果沒有內建的xxx外掛那麼將繼續查詢當前系統中是否存在protoc-gen-xxx命名的可執行程式,最終通過查詢到的外掛生成程式碼。所以我們使用–go_out,表示使用protoc-gen-go可執行程式。
如果我們新寫了一個protoc-gen-go-my命令,並且註冊外掛netrpc, 則可以使用命令 –go-my_out=plugins=netrpc。
protoc-gen-go
而這個可執行檔案裡面又實現了一層靜態外掛系統,比如protoc-gen-go內建了一個gRPC外掛,使用者可以通過--go_out=plugins=grpc
引數來生成gRPC相關程式碼,否則只會針對message生成相關程式碼。
自定義外掛
我們可以模仿protoc-gen-go,自定義一個外掛。
先看看protoc-gen-go原始碼的main函式(舊版本),所以只要往generator註冊自定義的外掛物件即可,不用修改這個main函式
package main
import (
"io/ioutil"
"os"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/protoc-gen-go/generator" //我們新寫的plugin會註冊到這裡
)
func main() {
g := generator.New()
data, err := ioutil.ReadAll(os.Stdin)
if err != nil {
g.Error(err, "reading input")
}
if err := proto.Unmarshal(data, g.Request); err != nil {
g.Error(err, "parsing input proto")
}
...
}
自定義plugin物件,plugins/netrpc.go
generator會處理proto檔案,生成generator.FileDescriptor物件儲存裡面的資訊。
package plugins
import (
"github.com/golang/protobuf/protoc-gen-go/generator"
"google.golang.org/protobuf/types/descriptorpb"
)
//自定義protoc-gen-go外掛,通過--go_out=plugins=netrpc 來生成go程式碼
type NetrpcPlugin struct {
*generator.Generator
}
func init() {
//註冊到generator
generator.RegisterPlugin(new(NetrpcPlugin))
}
func (p *NetrpcPlugin) Name() string {
return "netrpc"
}
func (p *NetrpcPlugin) Init(g *generator.Generator) {
p.Generator = g
}
func (p *NetrpcPlugin) GenerateImports(file *generator.FileDescriptor) {
if len(file.Service) > 0 {
p.genImportCode(file)
}
}
func (p *NetrpcPlugin) Generate(file *generator.FileDescriptor) {
for _, svc := range file.Service { //處理proto檔案定義的service
p.genServiceCode(svc)
}
}
func (p *NetrpcPlugin) genImportCode(file *generator.FileDescriptor) {
p.P("// TODO: import code")
}
func (p *NetrpcPlugin) genServiceCode(svc *descriptorpb.ServiceDescriptorProto) {
p.P("// TODO: service code, Name = " + svc.GetName())
}
編譯自定義外掛生成可執行檔案protoc-gen-go-my
go build -o protoc-gen-go-netrpc
cp protoc-gen-go-netrpc /home/csx/go/bin #把生成的可執行檔案複製到gopath/bin目錄
使用自定義的可執行檔案來處理hello.proto
protoc --go-netrpc_out=plugins=netrpc:. hello.proto
使用go-micro外掛編譯protobuf
該命令會在bin目錄下生成protoc-gen-micro(.exe),protoc編譯器利用protoc-gen-micro外掛將.proto檔案轉換為micro程式碼風格檔案
go get github.com/micro/protoc-gen-micro/v2
2.編譯.proto檔案,會生成greeter.pb.go, greeter.pb.mico.go
protoc --proto_path=. --micro_out=. --go_out=. proto/greeter.proto
grpc-gateway框架編譯protobuf
兩個命令會在$GOPATH/bin目錄下生成protoc-gen-go,protoc-gen-grpc-gateway
$GOPATH預設是cd ~/go
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
protoc-gen-go使用新倉庫
github.com/golang/protobuf已經準備作廢
使用新的庫
google.golang.org/protobuf
安裝go外掛
The compiler plugin protoc-gen-go
will be installed in $GOBIN
, defaulting to $GOPATH/bin
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
protoc --go_out=. hello.proto
grpc使用
新protoc-gen-go命令不再支援plugin引數,需要重新下載protoc-gen-go-grpc命令
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
protoc --go_out=. hello.proto #編譯message得到變數
protoc --go-grpc_out=. hello.proto #編譯其他資料,依賴message變數
需要生成兩個檔案,hello.pb.go, hello_grpc.pb.go. 合併為一條語句
protoc –go_out=. –go-grpc_out=. hello.proto
protobuf3語法
www.cnblogs.com/tohxyblog/p/897476...
本作品採用《CC 協議》,轉載必須註明作者和本文連結