基于Gin的Protobuf使用 | 青训营笔记

1,301 阅读3分钟

这是我参与 第五届青训营 伴学笔记创作活动的第5天

简介

基于小组决定使用gin框架搭设后端服务,特地研究了一下protobuf数据传输

protobuf 是一种高性能的数据传输方式,他比 xml 与 json 快 N 倍;

下面我们将使用 gin 框架下配置 protobuf


快速配置与使用

安装

下载 protoc 编译器:github 官网下载

我下载的是最新的 21.12 版本,点击“show all 28 assets”,在最底部找到 windows 版本,因为我的电脑是 64 位的,所以选择 win64

image.png


下载得到的压缩包,在 bin 内找到 protoc.exe

直接把他丢到 go 根目录下的 bin 文件夹(因为我们之前配置环境变量时已经指定了该文件夹,就不需要再为了 protoc.exe 指定一个新的文件夹)


安装 protoc-gen-go(这里使用的是老版本的,新版本的使用 google 源,这里为了快速上手就不演示了)
go get github.com/golang/protobuf/protoc-gen-go

下载完毕后来到我们的 $GOPATH,打开 bin 文件夹,把里面刚刚生成的 protoc-gen-go.exe 也丢到 go 根目录下的 bin 文件夹内


无论你使用什么 IDE,都建议安装一个 protobuf 插件,它能自动识别 proto 文件并提供代码补全;

如果你用的是 goland,推荐安装插件:Protobuf
如果你用的是 vscode,推荐安装插件:vscode-proto3


这还不算最恶心的,后面更恶心,请别反胃,慢慢看


文件结构

这是我在 goland 中单独创建的一个基于 gin 框架的项目,下面是对应文件以及文件夹的作用解释:

  1. config 配置文件夹,此次文章用不到
  2. files/protobuf 存储 proto 文件的地方
  3. files/protobuf/output 存储编译后的 proto 文件的地方
  4. src 里面有 main.go 文件

image.png


编写 user.proto

按照文件结构所述,新建文件:files/protobuf/user.proto

syntax = "proto3";

option go_package = "./output;service";

package service;

message Person {
    string name = 1;
    int32 age = 2;
    string email = 3;
}

syntax 表示当前使用的 proto 版本

option go_package 用于指定输出文件夹以及包名;
格式为 "path;package_name"
输出路径起始点为当前文件所在文件夹,所以 ./output 实际就是指 files/protobuf/output 文件夹
包名可以随意指定,但不要和你项目内的包名重合!

package 定义包名,这里的包名和 option go_package 字段定义的包名需要保持一致!

message 定义结构体

定义的结构体格式为: 类型 名称 = 序号
大小写不敏感,且定义的值只是表示序号,而不代表后续我们取出来的就是这些值!!!


编译输出

进入到 user.proto 所在文件夹 并打开命令行(特别特别特别要注意这里打开命令行的位置,不然相对路径搞错了无法编译可别怪我。。。)

生成指令语句格式:proto --go_out=编译后文件保存位置 proto文件或proto文件所在文件夹

所以我们不难得出生成语句:proto --go_out=./ user.proto
表示在当前文件夹下生成编译后文件,并且使用到的 proto 文件为 user.proto


编译完毕,自动创建 output 文件夹,文件夹内生成了一个 user.pb.go 文件


正式测试

累了不想打字了,自己看注释;

原理部分将会在后续的不远时间内进行补全呜呜呜呜;

func main() {
	router := gin.Default()

    // 1. 序列化过程
    // 实例化结构体
    // 注意这里的包名为我们在proto中定义的!
    // 使用&进行引用
	person := &service.Person{
		Name:  "what the???",
		Age:   10238,
		Email: "no way!",
	}

    // Marshal对结构体执行序列化
	bt, _ := proto.Marshal(person)
	fmt.Printf("%v\n", bt)

    // 2. 反序列化过程
    // 先实例化一个空的结构体
    // Unmarshal反序列化,参数一为序列化的数据,参数二为存储反序列化结果的变量
	unperson := &service.Person{}
	proto.Unmarshal(bt, unperson)

    // 反序列化后得到的结构体可以直接调用对应方法
    // 方法名可以去 user.pb.go 文件内查看
	fmt.Printf("otherArticle.GetAid(): %v\n", unperson.GetName())

	router.Run(":10001")
}