protobuf 简介

jsonprotobuf
语言无关、平台无关、可扩展的序列化结构数据格式

开发者可以通过Protobuf附带的工具,生成代码并实现将结构化数据序列化的功能。

安装 protoc 命令工具

protoc.protoprotobuf数据格式定义文件protobuf
环境变量目录$GOPATH/bin

安装 protoc-gen-go 插件

protoc.protoprotoc-gen-go
go installprotoc-gen-go
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
$GOPATH/binprotoc-gen-go.exeprotoc-gen-go.exe
protocprotoc-gen-go

proto 文件介绍

字段规则

message User {
  string username = 1;
  int32 age = 2;
  optional string password = 3;
  repeated string address = 4;
}
  • required:消息体中必填字段,不设置会导致编解码异常
  • optional: 消息体中可选字段
  • repeated: 消息体中可重复字段,重复的值的顺序会被保留.在go中重复的会被定义为切片。

字段映射

protoGoPythonC++
doublefloat64floatdouble
floatfloat32floatfloat
bytes[]bytestrstring
stringstringstr/unicodestring

默认值

protobuf3 删除了 protobuf2 中用来设置默认值的 default 关键字,取而代之的是protobuf3为各类型定义的默认值,也就是约定的默认值,如下表所示:

  • bool false
  • 整型 0
  • string 空字符串 “”
  • 枚举 第一个枚举元素的值,因为Protobuf3强制要求第一个枚举元素的值必须是0,所以枚举的默认值就是0
  • message 不是null,而是DEFAULT_INSTANCE

标识号

在消息体的定义中,每个字段都必须要有一个唯一的标识号,标识号是[0,2^29-1]范围内的一个整数。

message Person { 

  string name = 1;  // (位置1)
  int32 id = 2;  
  optional string email = 3;  
  repeated string phones = 4; // (位置4)
}

嵌套消息

message PersonInfo {
    message Person {
        string name = 1;
        int32 height = 2;
        repeated int32 weight = 3;
    } 
    repeated Person info = 1;
}

message PersonMessage {
	PersonInfo.Person info = 1;
}

protobuf数据格式的编码和解码

创建测试项目

testProtogo mod init testProto

编辑.proto源文件

protos
vim user.proto
// 指定的当前proto语法的版本,有2和3
syntax = "proto3";
//option go_package = "path;name"; ath 表示生成的go文件的存放地址,会自动生成目录的
// name 表示生成的go文件所属的包名
option go_package="../service";
// 指定等会文件生成出来的package
package service;

message User {
  string username = 1;
  int32 age = 2;
}

使用 protoc 命令生成go源码文件

service
# 编译user.proto之后输出到service文件夹
protoc --go_out=service protos/user.proto
service目录user.pb.go

测试

main.go
package main

import (
	"fmt"
	"google.golang.org/protobuf/proto"
	"testProto/service"
)

func main()  {
	user := &service.User{
		Username: "mszlu",
		Age: 20,
	}
	//转换为protobuf
	marshal, err := proto.Marshal(user)
	if err != nil {
		panic(err)
	}
	newUser := &service.User{}
	err = proto.Unmarshal(marshal, newUser)
	if err != nil {
		panic(err)
	}
	fmt.Println(newUser.String())
}

运行命令:

# 解决包依赖
go mod tidy
# 运行
go run .
# 输出
 username:"mszlu"  age:20

测试项目结构如下:

├── go.mod
├── go.sum
├── main.go
├── protos
│   └── user.proto
└── service
    └── user.pb.go

gRPC官方文档 https://grpc.io/docs/languages/go/quickstart/
gRPC教程 — 第一章 https://blog.csdn.net/Mr_XiMu/article/details/124852670
Go中的gRPC入门教程详解 https://www.jb51.net/article/242787.htm