這是一篇姊妹篇文章,淺析一下Go是如何實現protobuf編解碼的:
本編是第一篇。
Protocol buffers縮寫為protobuf,是由Google創造的一種用於序列化的標記語言,項目Github倉庫:https://github.com/protocolbuffers/protobuf。
Protobuf主要用於不同的程式語言的協作RPC場景下,定義需要序列化的數據格式。Protobuf本質上僅僅是一種用於交互的結構式定義,從功能上和XML、JSON等各種其他的交互形式都並無本質不同,只負責定義不負責數據編解碼。
其官方介紹如下:
Protocol buffers are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages.
protobuf是支持多種程式語言的,即多種程式語言的類型數據可以轉換成protobuf定義的類型數據,各種語言的類型對應可以看此介紹。
我們介紹一下protobuf對多語言的支持原理。protobuf有個程序叫protoc,它是一個編譯程序,負責把proto文件編譯成對應語言的文件,它已經支持了C++、C#、Java、Python,而對於Go和Dart需要安裝插件才能配合生成對於語言的文件。
對於C++,protoc可以把a.proto,編譯成a.pb.h和a.pb.cc。
對於Go,protoc需要使用插件protoc-gen-go,把a.proto,編譯成a.pb.go,其中包含了定義的數據類型,它的序列化和反序列化函數等。
敲黑板,對Go語言,protoc只負責利用protoc-gen-go把proto文件編譯成Go語言文件,並不負責序列化和反序列化,生成的Go語言文件中的序列化和反序列化操作都是只是wrapper。
那Go語言對protobuf的序列化和反序列化,是由誰完成的?
由github.com/golang/protobuf/proto完成,它負責把結構體等序列化成proto數據([]byte),把proto數據反序列化成Go結構體。
OK,原理部分就鋪墊這些,看一個簡單樣例,了解protoc和protoc-gen-go的使用,以及進行序列化和反序列化操作。
根據上面的介紹,Go語言使用protobuf我們要先安裝2個工具:protoc和protoc-gen-go。
安裝protoc和protoc-gen-go
首先去下載頁下載符合你系統的protoc,本文示例版本如下:
protoc的安裝步驟在readme.txt中:
To install, simply place this binary somewhere in your PATH.
把protoc-3.9.0-osx-x86_64/bin加入到PATH。
If you intend to use the included well known types then don』t forget tocopy the contents of the 『include』 directory somewhere as well, for exampleinto 『/usr/local/include/『.
如果使用已經定義好的類型,即上面include目錄*.proto文件中的類型,把include目錄下文件,拷貝到/usr/local/include/。
go get –u github.com/golang/protobuf/protoc-gen-go
檢查安裝,應該能查到這2個程序的位置:
fabric git:(release-1.4) which protoc
/usr/local/bin/protoc
fabric git:(release-1.4) which protoc-gen-go
/Users/shitaibin/go/bin/protoc-gen-go
創建了一個使用protoc的小玩具,項目地址Github: golang_step_by_step。
它的目錄結構如下:
protobuf git:(master) tree helloworld1
helloworld1
├── main.go
├── request.proto
└── types
└── request.pb.go
使用proto3,定義一個Request,request.proto內容如下:
// file: request.proto
syntax = "proto3";
package helloworld;
option go_package="./types";
message Request {
string data = 1;
}
$ protoc --go_out=. ./request.proto
--go_out指明了要把./request.proto編譯成Go語言文件,生成的是./types/request.pb.go,注意觀察一下為Request結構體生產的2個方法XXX_Unmarshal和XXX_Marshal,文件內容如下:
下面這段測試程序就是創建了一個請求,序列化又反序列化的過程。
運行結果:
helloworld1 git:(master) go run main.go
req: data:"Hello LIB"
unmarshaledReq: data:"Hello LIB"
以上都是鋪墊,下一節的proto包怎麼實現編解碼才是重點,protobuf用法可以去翻:
原文連結:http://lessisbetter.site/2019/08/26/protobuf-in-go/
本文作者:大彬,原創授權發布