google的protobuf這麼火,Go是如何實現protobuf編解碼的?—原理

這是一篇姊妹篇文章,淺析一下Go是如何實現protobuf編解碼的:

  1. Go是如何實現protobuf的編解碼的(1): 原理
  2. Go是如何實現protobuf的編解碼的(2): 源碼

本編是第一篇。

Protocol Buffers介紹

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.


Protocol buffers的多語言支持

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,其中包含了定義的數據類型,它的序列化和反序列化函數等。

google的protobuf這麼火,Go是如何實現protobuf編解碼的?—原理

敲黑板,對Go語言,protoc只負責利用protoc-gen-go把proto文件編譯成Go語言文件,並不負責序列化和反序列化,生成的Go語言文件中的序列化和反序列化操作都是隻是wrapper。

那Go語言對protobuf的序列化和反序列化,是由誰完成的?

由github.com/golang/protobuf/proto完成,它負責把結構體等序列化成proto數據([]byte),把proto數據反序列化成Go結構體。

google的protobuf這麼火,Go是如何實現protobuf編解碼的?—原理


OK,原理部分就鋪墊這些,看一個簡單樣例,瞭解protoc和protoc-gen-go的使用,以及進行序列化和反序列化操作。

一個Hello World樣例

根據上面的介紹,Go語言使用protobuf我們要先安裝2個工具:protoc和protoc-gen-go。

安裝protoc和protoc-gen-go

首先去下載頁下載符合你係統的protoc,本文示例版本如下:

google的protobuf這麼火,Go是如何實現protobuf編解碼的?—原理

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/。

安裝protoc-gen-go:

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

Hello world

創建了一個使用protoc的小玩具,項目地址Github: golang_step_by_step。

它的目錄結構如下:

➜ protobuf git:(master) tree helloworld1
helloworld1
├── main.go
├── request.proto
└── types
└── request.pb.go

定義proto文件

使用proto3,定義一個Request,request.proto內容如下:

// file: request.proto
syntax = "proto3";
package helloworld;
option go_package="./types";
message Request {
string data = 1;
}
  • syntax:protobuf版本,現在是proto3
  • package:不完全等價於Go的package,最好另行設定go_package,指定根據protoc文件生成的go語言文件的package名稱。
  • message:會編譯成Go的struct。
  • string data = 1:代表request的成員data是string類型,該成員的id是1,protoc給每個成員都定義一個編號,編解碼的時候使用編號代替使用成員名稱,壓縮數據量。

編譯proto文件

$ protoc --go_out=. ./request.proto

--go_out指明瞭要把./request.proto編譯成Go語言文件,生成的是./types/request.pb.go,注意觀察一下為Request結構體生產的2個方法XXX_Unmarshal和XXX_Marshal,文件內容如下:

google的protobuf這麼火,Go是如何實現protobuf編解碼的?—原理

google的protobuf這麼火,Go是如何實現protobuf編解碼的?—原理

編寫Go語言程序

下面這段測試程序就是創建了一個請求,序列化又反序列化的過程。

google的protobuf這麼火,Go是如何實現protobuf編解碼的?—原理

運行結果:

➜ helloworld1 git:(master) go run main.go
req: data:"Hello LIB"
unmarshaledReq: data:"Hello LIB"

以上都是鋪墊,下一節的proto包怎麼實現編解碼才是重點,protobuf用法可以去翻:

  1. 官方介紹:protoc3介紹,編碼介紹,Go教程
  2. 煎魚grpc系列文章

參考文章

  • https://tech.meituan.com/2015/02/26/serialization-vs-deserialization.html
  • 《序列化和反序列化》出自美團技術團隊,值得一讀。
  • https://github.com/golang/protobuf
  • Go支持protocol buffer的倉庫,Readme,值得詳讀。
  • https://developers.google.com/protocol-buffers/docs/gotutorial
  • Google Protocol Buffers的Go語言tutorial,值得詳細閱讀和實操。
  • https://developers.google.com/protocol-buffers/docs/overview
  • Google Protocol Buffers的Overview,介紹了什麼是Protocol Buffers,它的原理、歷史(起源),以及和XML的對比,必讀。
  • https://developers.google.com/protocol-buffers/docs/proto3
  • 《Language Guide (proto3)》這篇文章介紹了proto3的定義,也可以理解為.proto文件的語法,就如同Go語言的語法,不懂語法怎麼編寫.proto文件?讀這篇文章會了解很多原理,以及可以少踩坑,必讀。
  • https://developers.google.com/protocol-buffers/docs/reference/go-generated
  • 《Go Generated Code》這篇文章詳細介紹了protoc是怎麼用.protoc生成.pb.go的,可選。
  • https://developers.google.com/protocol-buffers/docs/encoding#
  • 《Protocol Buffers Encoding》這篇介紹編碼原理,可選。
  • https://godoc.org/github.com/golang/protobuf/proto
  • 《package proto文檔》可以把proto包當做Go語言操作protobuf數據的SDK,它實現了結構體和protobuf數據的轉換,它和.pb.go文件配合使用。

原文鏈接:http://lessisbetter.site/2019/08/26/protobuf-in-go/


分享到:


相關文章: