为什么要使用protobuf
最近的项目中,一直使用Json做数据传输。Json用起来的确很方便。但相对于protobuf数据量更大些。做一个移动端应用,为用户省点流量还是很有必要的。正好也可以学习一下protobuf的使用
跟Json相比protobuf性能更高,更加规范
- 编解码速度快,数据体积小
- 使用统一的规范,不用再担心大小写不同导致解析失败等蛋疼的问题了
但也失去了一些便利性
- 改动协议字段,需要重新生成文件。
- 数据没有可读性
protobuf github: https://github.com/protocolbuffers/protobuf/releases
本文使用的是 https://github.com/protocolbuffers/protobuf/releases/download/v3.9.0/protobuf-all-3.9.0.tar.gz
下载到linux中,编译安装
# 下载安装包
[root@izj6c4jirdug8kh3uo6rdez package]# wget https://github.com/protocolbuffers/protobuf/releases/download/v3.9.0/protobuf-all-3.9.0.tar.gz
# 解压
[root@izj6c4jirdug8kh3uo6rdez package]# tar -zxvf proto*
# 切换到解压后的目录
[root@izj6c4jirdug8kh3uo6rdez protobuf-3.9.0]# cd proto*
# 设置安装目录
[root@izj6c4jirdug8kh3uo6rdez protobuf-3.9.0]# ./configure --prefix=/usr/local/proto
# 编译安装
[root@izj6c4jirdug8kh3uo6rdez protobuf-3.9.0]# make && make install
# 添加到bin目录
[root@izj6c4jirdug8kh3uo6rdez protobuf-3.9.0]# ln -s /usr/local/proto/bin/protoc /usr/bin/protoc
# 查看版本
[root@izj6c4jirdug8kh3uo6rdez protobuf-3.9.0]# protoc --version
libprotoc 3.9.0
安装goprotobuf
# protoc-gen-go是用来将protobuf的的代码转换成go语言代码的一个插件
[root@izj6c4jirdug8kh3uo6rdez protobufffile]# go get -u github.com/golang/protobuf/protoc-gen-go
# proto是protobuf在golang中的接口模块
[root@izj6c4jirdug8kh3uo6rdez protobufffile]# go get -u github.com/golang/protobuf/proto
# 设置 protoc-gen-go 命令
[root@izj6c4jirdug8kh3uo6rdez protobufffile]# find / -name protoc-gen-go
/usr/local/go/gopath/bin/protoc-gen-go
/usr/local/go/gopath/pkg/mod/github.com/golang/protobuf@v1.3.2/protoc-gen-go
/usr/local/go/gopath/pkg/mod/github.com/golang/protobuf@v1.3.1/protoc-gen-go
[root@izj6c4jirdug8kh3uo6rdez protobufffile]# ln -s /usr/local/go/gopath/bin/protoc-gen-go /usr/bin/protoc-gen-go
目录结构如下:
项目根目录是 protobufffile
protobufffile的目录结构
├── protobuf # proto文件统一存放目录
│ ├── protobuf.proto # proto文件
├── main.go # 项目单入口
下面,我们根据目录结构,从上往下建立文件夹和文件
建立文件夹和文件 protobufffile/protobuf/protobuf.proto ,protobuf.proto 内容如下:
//指定版本
//注意proto3与proto2的写法有些不同
syntax = "proto3";
//包名,通过protoc生成时go文件时
package protobuf;
//声明一个消息体描述一个请求或者响应的消息格式
message HelloWorld {
int32 id = 1;
string name = 2;
int32 sin = 3;
}
建立文件 protobufffile/main.go ,main.go 内容如下:
package main
import (
"fmt"
"os"
"io"
"github.com/golang/protobuf/proto"
stProto "protobufffile/protobuf"
)
func main() {
//写入数据
protobuffWrite()
//读取数据
protobuffRead()
}
func protobuffWrite(){
//初始化protobuf数据格式
msg := &stProto.HelloWorld{
Id: *proto.Int32(17),
Name: *proto.String("hello world"),
Sin: *proto.Int32(18),
}
filename := "./protobufffile.txt"
fmt.Printf("使用protobuf创建文件 %s\n",filename)
fObj,_ := os.Create(filename) //创建文件
defer fObj.Close() //关闭文件 ,defer 会在程序最后运行
buffer,_ := proto.Marshal(msg) //序列化数据
fObj.Write(buffer) //写入文件
}
func protobuffRead(){
filename := "protobufffile.txt"
file,fileErr := os.Open(filename) //打开文件
checkError(fileErr)
defer file.Close()//关闭文件 ,defer 会在程序最后运行
fs,fsErr := file.Stat()
checkError(fsErr)
buffer := make([]byte,fs.Size()) //创建 byte切片
//把file文件内容读取到buffer
_,readErr := io.ReadFull(file,buffer)
checkError(readErr)
//初始化pb结构体对象并将buffer中的文件内容读取到pb结构体中
msg := &stProto.HelloWorld{}
pbErr := proto.Unmarshal(buffer, msg) //反序列化数据
checkError(pbErr)
fmt.Printf("读取文件:%s \r\nname:%s\nid:%d\nopt:%d\n",filename,msg.GetName(),msg.GetId(),msg.GetSin())
}
//检查错误
func checkError(err error) {
if err != nil {
fmt.Println(err.Error())
os.Exit(-1)
}
}
切换到protobufffile/protobuf目录中,编译 .proto
文件,生成 Go 语言文件
[root@izj6c4jirdug8kh3uo6rdez protobufffile]# cd protobuf
[root@izj6c4jirdug8kh3uo6rdez protobuf]# ll
total 4
-rw-r--r-- 1 root root 302 Aug 6 12:37 protobuf.proto
[root@izj6c4jirdug8kh3uo6rdez protobuf]# protoc --go_out=. *.proto
[root@izj6c4jirdug8kh3uo6rdez protobuf]# ll
total 8
-rw-r--r-- 1 root root 3186 Aug 6 12:38 protobuf.pb.go
-rw-r--r-- 1 root root 302 Aug 6 12:37 protobuf.proto
切换到protobufffile目录中, 初始化包
[root@izj6c4jirdug8kh3uo6rdez protobufffile]# go mod init protobufffile
go: creating new go.mod: module protobufffile
打包项目
[root@izj6c4jirdug8kh3uo6rdez protobufffile]# go build
运行
[root@izj6c4jirdug8kh3uo6rdez protobufffile]# ./protobufffile
使用protobuf创建文件 ./protobufffile.txt
读取文件:protobufffile.txt
name:hello world
id:17
opt:18
参考:https://www.jianshu.com/p/f4051569fd32
参考:https://segmentfault.com/a/1190000009277748