七叶笔记 » golang编程 » google的protobuf这么火,Go是如何实现protobuf编解码的?—原理

google的protobuf这么火,Go是如何实现protobuf编解码的?—原理

这是一篇姊妹篇文章,浅析一下Go是如何实现protobuf编解码的:

  1. Go是如何实现protobuf的编解码的(1): 原理
  2. Go是如何实现protobuf的编解码的(2): 源码

本编是第一篇。

Protocol Buffers介绍

Protocol buffers缩写为protobuf,是由Google创造的一种用于 序列化 的标记语言,项目 Github 仓库:。

Protobuf主要用于不同的 编程语言 的协作RPC场景下,定义需要序列化的数据格式。Protobuf本质上仅仅是 一种用于交互的结构式定义 ,从功能上 和XML、JSON 等各种其他的交互形式都 并无本质不同,只负责定义不负责数据编解码

其官方介绍如下:

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,其中包含了定义的数据类型,它的序列化和反序列化函数等。

敲黑板,对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的使用,以及进行序列化和反序列化操作。

一个Hello World样例

根据上面的介绍,Go语言使用protobuf我们要先安装2个工具:protoc和protoc-gen-go。

安装protoc和protoc-gen-go

首先去下载页下载符合你系统的protoc,本文示例版本如下:

protoc的安装 步骤在readme.txt中:

To install, simply place this bin ary somewhere in your PATH.

把protoc-3.9.0-osx-x86_64/bin加入到PATH。

If you intend to use the include d 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,文件内容如下:

编写Go语言程序

下面这段测试程序就是创建了一个请求,序列化又反序列化的过程。

运行结果:

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

以上都是铺垫,下一节的proto包怎么实现编解码才是重点,protobuf用法可以去翻:

  1. 官方介绍:protoc3介绍,编码介绍,Go教程
  2. 煎鱼grpc系列文章

参考文章

  • 《序列化和反序列化》出自美团技术团队,值得一读。
  • Go支持protocol buffer的仓库,Readme,值得详读。
  • Google Protocol Buffers的Go语言tutorial,值得详细阅读和实操。
  • Google Protocol Buffers的Overview,介绍了什么是Protocol Buffers,它的原理、历史(起源),以及和XML的对比,必读。
  • 《Language Guide (proto3)》这篇文章介绍了proto3的定义,也可以理解为.proto文件的语法,就如同Go语言的语法,不懂语法怎么编写.proto文件?读这篇文章会了解很多原理,以及可以少踩坑,必读。
  • 《Go Generated Code》这篇文章详细介绍了protoc是怎么用.protoc生成.pb.go的,可选。
  • #
  • 《Protocol Buffers Encoding》这篇介绍编码原理,可选。
  • 《package proto文档》可以把proto包当做Go语言操作protobuf数据的SDK,它实现了结构体和protobuf数据的转换,它和.pb.go文件配合使用。

原文链接:

本文作者:大彬,原创授权发布

相关文章