Golang(Go语言)中Protobuf的使用

2023-11-07

什么是protobuf

protobuf也叫protocol buffer是google 的一种数据交换的格式,它独立于语言,独立于平台。google 提供了多种语言的实现:java、c#、c++、go 和 python,每一种实现都包含了相应语言的编译器以及库文件。

由于它是一种二进制的格式,比使用 xml 、json进行数据交换快许多。可以把它用于分布式应用之间的数据通信或者异构环境下的数据交换。作为一种效率和兼容性都很优秀的二进制数据传输格式,可以用于诸如网络传输、配置文件、数据存储等诸多领域。

一、环境的搭建

1.下载protobuf的编译器protoc 
访问https://github.com/google/protobuf/releases  
下载解压出protoc.exe(bin目录下的文件)文件放入gopath下的bin目录;

2.下载protobuf编译器所需插件 
用git下载protoc在go下运行所需插件(执行): go get github.com/golang/protobuf(gopath的bin目录会生成protoc-gen-go.exe), 
此时在gopath的bin目录下你会看到:

二、protobuf的使用

1、新建test.proto文件,protobuf内容如下:

syntax="proto3"; //版本号
package main;  //包名
enum ClassName{   //枚举
    class1=0;  //标号 必须从 0开始
    class2=1;
    class3=2;
}
message Student{ //消息,对应于Go的结构体
  string name=1; //1:标号,唯一 即可(相当于数据库中的Id,不一定要从1 ,2的顺序依次排列。)
  int32 age=2;  //必须指定整型的范围,如int32,int64
  string address=3;
  ClassName cn=4;
}
message Students{
   repeated Student person=1;  // repeated 修饰,相当于Go中切片
   string school=2;
}

protobuf类型如下:

2、生成Go文件

生成go文件的命令:protoc --go_out=. test.proto  (其中:test.proto为 以上内容对应的文件名)

生成的test.pb.go文件内容如下:

// Code generated by protoc-gen-go. DO NOT EDIT.
// source: test.proto

package main
import (
	fmt "fmt"
	proto "github.com/golang/protobuf/proto"
	math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type ClassName int32
const (
	ClassName_class1 ClassName = 0
	ClassName_class2 ClassName = 1
	ClassName_class3 ClassName = 2
)
var ClassName_name = map[int32]string{
	0: "class1",
	1: "class2",
	2: "class3",
}
var ClassName_value = map[string]int32{
	"class1": 0,
	"class2": 1,
	"class3": 2,
}
func (x ClassName) String() string {
	return proto.EnumName(ClassName_name, int32(x))
}
func (ClassName) EnumDescriptor() ([]byte, []int) {
	return fileDescriptor_c161fcfdc0c3ff1e, []int{0}
}
type Student struct {
	Name                 string    `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
	Age                  int32     `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
	Address              string    `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"`
	Cn                   ClassName `protobuf:"varint,4,opt,name=cn,proto3,enum=main.ClassName" json:"cn,omitempty"`
	XXX_NoUnkeyedLiteral struct{}  `json:"-"`
	XXX_unrecognized     []byte    `json:"-"`
	XXX_sizecache        int32     `json:"-"`
}

func (m *Student) Reset()         { *m = Student{} }
func (m *Student) String() string { return proto.CompactTextString(m) }
func (*Student) ProtoMessage()    {}
func (*Student) Descriptor() ([]byte, []int) {
	return fileDescriptor_c161fcfdc0c3ff1e, []int{0}
}
func (m *Student) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_Student.Unmarshal(m, b)
}
func (m *Student) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_Student.Marshal(b, m, deterministic)
}
func (m *Student) XXX_Merge(src proto.Message) {
	xxx_messageInfo_Student.Merge(m, src)
}
func (m *Student) XXX_Size() int {
	return xxx_messageInfo_Student.Size(m)
}
func (m *Student) XXX_DiscardUnknown() {
	xxx_messageInfo_Student.DiscardUnknown(m)
}

var xxx_messageInfo_Student proto.InternalMessageInfo

func (m *Student) GetName() string {
	if m != nil {
		return m.Name
	}
	return ""
}

func (m *Student) GetAge() int32 {
	if m != nil {
		return m.Age
	}
	return 0
}

func (m *Student) GetAddress() string {
	if m != nil {
		return m.Address
	}
	return ""
}

func (m *Student) GetCn() ClassName {
	if m != nil {
		return m.Cn
	}
	return ClassName_class1
}

type Students struct {
	Person               []*Student `protobuf:"bytes,1,rep,name=person,proto3" json:"person,omitempty"`
	School               string     `protobuf:"bytes,2,opt,name=school,proto3" json:"school,omitempty"`
	XXX_NoUnkeyedLiteral struct{}   `json:"-"`
	XXX_unrecognized     []byte     `json:"-"`
	XXX_sizecache        int32      `json:"-"`
}

func (m *Students) Reset()         { *m = Students{} }
func (m *Students) String() string { return proto.CompactTextString(m) }
func (*Students) ProtoMessage()    {}
func (*Students) Descriptor() ([]byte, []int) {
	return fileDescriptor_c161fcfdc0c3ff1e, []int{1}
}

func (m *Students) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_Students.Unmarshal(m, b)
}
func (m *Students) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_Students.Marshal(b, m, deterministic)
}
func (m *Students) XXX_Merge(src proto.Message) {
	xxx_messageInfo_Students.Merge(m, src)
}
func (m *Students) XXX_Size() int {
	return xxx_messageInfo_Students.Size(m)
}
func (m *Students) XXX_DiscardUnknown() {
	xxx_messageInfo_Students.DiscardUnknown(m)
}

var xxx_messageInfo_Students proto.InternalMessageInfo

func (m *Students) GetPerson() []*Student {
	if m != nil {
		return m.Person
	}
	return nil
}

func (m *Students) GetSchool() string {
	if m != nil {
		return m.School
	}
	return ""
}

func init() {
	proto.RegisterEnum("main.ClassName", ClassName_name, ClassName_value)
	proto.RegisterType((*Student)(nil), "main.Student")
	proto.RegisterType((*Students)(nil), "main.Students")
}

func init() { proto.RegisterFile("test.proto", fileDescriptor_c161fcfdc0c3ff1e) }

var fileDescriptor_c161fcfdc0c3ff1e = []byte{
	// 204 bytes of a gzipped FileDescriptorProto
	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x3c, 0x8f, 0xcd, 0x4e, 0xc5, 0x20,
	0x10, 0x85, 0x85, 0x56, 0xae, 0x1d, 0xa3, 0x92, 0x59, 0x18, 0x76, 0x92, 0x9b, 0x98, 0x10, 0x17,
	0x35, 0xf6, 0x3e, 0x82, 0x2b, 0x37, 0x2e, 0xf0, 0x09, 0x90, 0x12, 0x7f, 0xd2, 0x42, 0xd3, 0xc1,
	0xf7, 0x37, 0x45, 0xec, 0xee, 0xfb, 0x72, 0xe0, 0xcc, 0x0c, 0x40, 0x0e, 0x94, 0xfb, 0x65, 0x4d,
	0x39, 0x61, 0x3b, 0xbb, 0xaf, 0x78, 0xfc, 0x86, 0xc3, 0x5b, 0xfe, 0x19, 0x43, 0xcc, 0x88, 0xd0,
	0x46, 0x37, 0x07, 0xc5, 0x34, 0x33, 0x9d, 0x2d, 0x8c, 0x12, 0x1a, 0xf7, 0x11, 0x14, 0xd7, 0xcc,
	0x9c, 0xdb, 0x0d, 0x51, 0xc1, 0xc1, 0x8d, 0xe3, 0x1a, 0x88, 0x54, 0x53, 0x1e, 0xfe, 0x2b, 0xde,
	0x01, 0xf7, 0x51, 0xb5, 0x9a, 0x99, 0xeb, 0xe1, 0xa6, 0xdf, 0xda, 0xfb, 0xe7, 0xc9, 0x11, 0xbd,
	0xba, 0x39, 0x58, 0xee, 0xe3, 0xf1, 0x05, 0x2e, 0xea, 0x2c, 0xc2, 0x7b, 0x10, 0x4b, 0x58, 0x29,
	0x45, 0xc5, 0x74, 0x63, 0x2e, 0x87, 0xab, 0xbf, 0x0f, 0x35, 0xb7, 0x35, 0xc4, 0x5b, 0x10, 0xe4,
	0x3f, 0x53, 0x9a, 0xca, 0x0a, 0x9d, 0xad, 0xf6, 0xf0, 0x08, 0xdd, 0xde, 0x8d, 0x00, 0xc2, 0x6f,
	0xf2, 0x24, 0xcf, 0x76, 0x1e, 0x24, 0xdb, 0xf9, 0x24, 0xf9, 0xbb, 0x28, 0x47, 0x9f, 0x7e, 0x03,
	0x00, 0x00, 0xff, 0xff, 0x67, 0x97, 0x87, 0x75, 0x02, 0x01, 0x00, 0x00,
}

可以看成,将protobuf message对应的内容生成结构体,通过GetXX方法来获取对应的值。

3、Golang的使用

package main

import (
	"fmt"
	"github.com/golang/protobuf/proto"
)

func main() {
	s1:=&Student{} //第一个学生信息
	s1.Name="jz01"
	s1.Age=23
	s1.Address="cq"
	s1.Cn=ClassName_class2 //枚举类型赋值
	ss:=&Students{}
	ss.Person=append(ss.Person,s1) //将第一个学生信息添加到Students对应的切片中
	s2:=&Student{}  //第二个学生信息
	s2.Name="jz02"
	s2.Age=25
	s2.Address="cd"
	s2.Cn=ClassName_class3
	ss.Person=append(ss.Person,s2)//将第二个学生信息添加到Students对应的切片中
	ss.School="cqu"
	fmt.Println("Students信息为:",ss)

	// Marshal takes a protocol buffer message
	// and encodes it into the wire format, returning the data.
	buffer, _ := proto.Marshal(ss)
	fmt.Println("序列化之后的信息为:",buffer)
	// 	Use UnmarshalMerge to preserve and append to existing data.
	data:=&Students{}
	proto.Unmarshal(buffer,data)
	fmt.Println("反序列化之后的信息为:",data)
}

注:序列化以后数据被转换成二进制类型(即适合于网络传输的protobuf类型,也就是将结构体类型转换为protobuf类型),反序列化后直接写入(转换)对应的结构体类型(也就是将protobuf类型转换为对应的结构体类型)。 

 

了解更多Go语言知识https://study.163.com/course/introduction/1210620804.htm

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Golang(Go语言)中Protobuf的使用 的相关文章

  • go struct{} 空结构体的特点和作用

    空结构体的特点和作用 参考代码 package main import fmt unsafe func main empStruct 空结构体的实例和作用 func empStruct 空结构体的特点 1 不占用内存 2 地址不变 var
  • 使用Docker registry镜像创建私有仓库

    2015 01 25 wcdj 摘要 安装Docker后 可以通过官方提供的registry镜像来简单搭建一套本地私有仓库环境 本文记录简单的搭建过程 1 使用registry启动私有仓库的容器 docker run d p 5000 50
  • golang之跨语言ipc通信

    1 golang之跨语言ipc通信 文章目录 1 golang之跨语言ipc通信 1 1 unix domain Socket unix域套接字 介绍 1 2 IPC SOCKET通信 1 2 1 函数及地址定义介绍 1 2 2 UNIX
  • go字符串详解

    文章目录 摘要 1 byte和rune类型 2 字符串 string 3 练习 反转字符串 摘要 go字符串结构体包含 指向底层存储数组的指针 字符串长度 字符串按utf 8将字符编码成二进制数 然后存储在byte数组中 因为utf 8编码
  • Go语言入门【09】结构体

    结构体 相比于Java 在Go语言中没有类的概念 但是多了结构体 结构体与Java中的类很像 是表示一系列同一类型或不同类型的数据构成的数据集合 例如可以将学生抽象成一个结构体 每一个学生有以下属性 Name 姓名 Age 年龄 Gende
  • Go语言实现区块链与加密货币-Part3(交易优化,单机模拟多节点通信)

    交易 二 在这个系列文章的一开始 我们就提到了 区块链是一个分布式数据库 不过在之前的文章中 我们选择性地跳过了 分布式 这个部分 而是将注意力都放到了 数据库 部分 到目前为止 我们几乎已经实现了一个区块链数据库的所有元素 今天 我们将会
  • Go_关键字、编译、转义字符

    关键字 关键字是指被go语言赋予了特殊含义的单词 共25个 关键字不能用于自定义名字 只能在特定语法结构中使用 break default func interface select case defer go map struct cha
  • Jenkins系列:3、wsl/ubuntu安装Jenkins及Jenkins构建可交叉编译的go程序

    Jenkins系列 3 wsl ubuntu安装Jenkins及Jenkins构建可交叉编译的go程序 文章目录 Jenkins系列 3 wsl ubuntu安装Jenkins及Jenkins构建可交叉编译的go程序 1 前言 2 wsl
  • go 进阶 gin实战相关: 五. gin_scaffold 企业脚手架

    目录 一 gin scaffold 企业级脚手架 二 gin scaffold 脚手架安装及使用演示 文件分层解释 开始使用 1 配置开启go mod 功能 2 下载 安装 gin scaffold 3 整合 golang common 4
  • Golang协程与通道整理

    协程goroutine 不由OS调度 而是用户层自行释放CPU 从而在执行体之间切换 Go在底层进行协助实现 涉及系统调用的地方由Go标准库协助释放CPU 总之 不通过OS进行切换 自行切换 系统运行开支大大降低 通道channel 并发编
  • Golang三剑客之Pflag、Viper、Cobra

    如何构建应用框架 想知道如何构建应用框架 首先你要明白 一个应用框架包含哪些部分 在我看来 一个应用框架需要包含以下 3 个部分 命令行参数解析 主要用来解析命令行参数 这些命令行参数可以影响命令的运行效果 配置文件解析 一个大型应用 通常
  • 基于Go语言实现简易Web应用

    目录 前言 Go语言特点 写在使用Go语言实现Web应用前面 创建Web服务器 声明一个结构体操作 加入中间件的使用 使用静态文件服务器 最后 前言 在编程语言中 近几年问世的几个新语言都是非常不错的 比如Go Python Rust等等
  • 【go语言开发】loglus日志框架的使用

    本文将简单介绍loglus框架的基本使用 并给出demo 文章目录 前言 Loglus常见用法 自定义日志级别 使用字段钩子 输出到多个位置 使用钩子实现自定义日志处理 demo
  • go-zero开发入门之网关往rpc服务传递数据1

    go zero 的网关往 rpc 服务传递数据时 可以使用 headers 但需要注意前缀规则 否则会发现数据传递不过去 或者对方取不到数据 go zero 的网关对服务的调用使用了第三方库 grpcurl 入口函数为 InvokeRPC
  • 【golang】go执行shell命令行的方法( exec.Command )

    所需包 import os exec cmd 的用法 cmd exec Command ls lah ls是命令 后面是参数 e cmd Run 多个参数的要分开传入 如 ip link show bond0 cmd
  • [每周一更]-(第55期):Go的interface

    参考地址 https juejin cn post 6978322067775029261 https gobyexample com interfaces https go dev tour methods 9 介绍下Go的interfa
  • Golang拼接字符串性能对比

    g o l a n g golang g o l an g
  • go cannot find package “github.com/gorilla/websocket“解读

    Go无法找到包 github com gorilla websocket 的解决方案 在Go开发过程中 我们经常会依赖第三方库来简化开发工作 而使用 go get 命令安装这些库时 有时候我们可能会遇到类似于以下错误的情况 plaintex
  • 【go语言】结构体数据填充生成md错误码文件

    这里使用pongo2这个模版引擎库进行md文件渲染 GitHub flosch pongo2 Django syntax like template engine for Go package main import fmt github
  • 【go语言】读取toml文件

    一 简介 TOML 全称为Tom s Obvious Minimal Language 是一种易读的配置文件格式 旨在成为一个极简的数据序列化语言 TOML的设计原则之一是保持简洁性 易读性 同时提供足够的灵活性以满足各种应用场景 TOML

随机推荐

  • vue配置开发环境和生产环境调用不同的域名以及跨域问题

    注意 这里vue项目与后端是前后端完全分离的 所有请求后端的地址是不一样的 安装axios npm install axios 然后 npm install save axios vue axios 用到post请求时 需要安装qs imp
  • Apache RocketMQ 5.0 消息进阶:如何支撑复杂的业务消息场景?

    一致性 首先来看 RocketMQ 的第一个特性 事务消息 事务消息是 RocketMQ 与一致性相关的特性 也是 RocketMQ 有别于其他消息队列的最具区分度的特性 以大规模电商系统为例 付款成功后会在交易系统中订单数据库将订单状态更
  • #101. 级数求和(3月31日)

    一 这题很简单我们只要注意高精度就行了 我一开始就是使用int型 傻傻算半天 int型 1 任何数 都只得整数 所以我们要用double来计算 只要从1开始一直网上循环摘要当我们的sn大于p时我们就停止循环 这题就是这样只要注意高精度就行了
  • linux链接jsoncpp库时,报一堆标准库错误的解决方法

    最近在一个工程中链接jsoncpp库 Makefile文件中添加包含路径代码 I usr local include json 编译时报错 usr include stdio h 821 错误 FILE 在此作用域中尚未声明 usr inc
  • 隐患重重遭诟病 细数固态硬盘“七宗罪”

    此内容转自网络 本人认为文章内容优秀 只作收藏 作为自己的知识库 并不用他用 原文链接地址为 http ssd zol com cn 471 4715723 all html 隐患重重遭诟病 细数固态硬盘 七宗罪 2015 02 28 19
  • vue.js -- slot插槽

    slot插槽 子组件提供给父组件使用的占位符 表示父组件可以占位符中填充内容 填充的内容会替换子组件的标签 插槽显不显示 怎样显示是由父组件来控制的 而插槽在哪里显示就由子组件来进行控制 slot作用域 slot在哪里调用 就使用哪里的数据
  • 数据管道(data pipeline)与ETL管道(ETL pipeline)的区别

    数据管道与ETL管道 这两个词的意义是相近的 差别比较微小 有时候很多人会混用 ETL管道 描述的是一组进程 实现将数据从一个系统抽取出来 经过转换 最终再加载到其他数据库或数据仓库中 数据管道 是一个比ETL管道更加通用的术语 只要是实现
  • 生成式AI:为开发者设计的革命性工具

    随着人工智能技术的飞速发展 生成式AI已成为许多领域的关键技术 生成式AI是指一类人工智能技术 能够通过学习数据集的内在规律和相关性 生成全新的 真实的 有用的数据 这种技术已经被广泛应用于图像 语音 自然语言处理等领域 成为人工智能领域的
  • 以太坊虚拟机EVM的工作原理是怎样的

    以太坊虚拟机EVM的工作原理是怎样的 如果你打算尝试在以太坊区块链上开发智能合约 或者已经在该领域工作了一段时间 可能会遇到EVM一词 EMV是太坊虚拟机的缩写 虚拟机本质上是在执行代码和执行的机器之间创建一个抽象级别 需要这一层抽象来提高
  • android系统 分辨率对应资源文件

    分辨率对比 ldpi 240x320 mdpi 320x480 hdpi 480x800 480x854 xhdpi 至少960 720 xxhdpi 1280 720 或 ldpi QVGA 240 320 mdpi HVGA 320 4
  • C++const修饰变量,函数,类

    const修饰变量 const的作用是 在编写程序过程中 因为我们会调用各种函数 假如我们并不想让某个已经赋了初值的变量在程序运行过程中受到改变 因此我们用const来作为关键字来修饰 定义格式 const typename 变量名 con
  • vue中 根据判断条件添加一个或多个style,及class的写法

    style 写法
  • 【pygame】font 模块

    pygame font Pygame 中加载和表示字体的模块 函数 pygame font init 初始化字体模块 pygame font quit 还原字体模块 pygame font get init 检查字体模块是否被初始化 pyg
  • libmad 解码mp3并且播放测试

    测试环境 window64 codeblock mingw64 下载libmad源码后发现自带的minimad c是用了linux的API 所以修改了下 将 F d mp3音乐文件解码后将pcm数据写入F d pcm 并且用ffplay播放
  • 阿里 前端 规范_阿里前端开发规范

    前端代码规范 Front Standard Guide 前端 JS 项目开发规范 规范的目的是为了编写高质量的代码 让你的团队成员每天得心情都是愉悦的 大家在一起是快乐的 引自 阿里规约 的开头片段 现代软件架构的复杂性需要协同开发完成 如
  • 【Liunx常用操作】利用iso镜像制作并使用本地yum源(CentOS7.6为例)

    提示 为保证文章的正确性和实用性 文章内容可能会不定时优化改进 若您有建议或者文章存在错误请私信留言或评论指正 下面以CentOS7 6操作系统为例 介绍具体的操作步骤 如果本文对你有帮助 记得关注加收藏 1 文章前言 在私网环境中部署的L
  • 【多线程中的线程安全问题】线程互斥

    1 线程间的互斥相关背景概念 先来看看一些基本概念 1 临界资源 多线程执行流共享的资源就叫做临界资源 2 临界区 每个线程内部 访问临界资源的代码 就叫做临界区 3 互斥 任何时刻 互斥保证有且只有一个执行流进入临界区 访问临界资源 通常
  • uni-app 打包之后日志输出和调试

    背景 真机调试时console log可以在控制台输出 但是 打包上线后 我们想查看apk的运行情况和调试日志 竟然官网没有方式 只有android app记录运行日志 通过abd指令 这是最无语的事 我还得学abd指令 逗我呢 反正收集用
  • 【木头Cocos2d-x 032】我是定时器(第01章)—我爱单线程之schedule介绍

    我是定时器第01章 我爱单线程之schedule介绍 本来今天我应该要做其它事情的 但是和一位网友提起了schedule 我无法按捺心中对写教程的热血和冲动 所以我就决定要写关于schedule的使用心得了 小若 我噗 永远都是那么唠叨 笨
  • Golang(Go语言)中Protobuf的使用

    什么是protobuf protobuf也叫protocol buffer是google 的一种数据交换的格式 它独立于语言 独立于平台 google 提供了多种语言的实现 java c c go 和 python 每一种实现都包含了相应语