1. 前言

工作几年了。ITDragon龙 的编程语言从熟悉的Java,到喜欢的Kotlin,最后到一言难尽的Golang。常用的数据交换格式也从xml到json,最后到现在的protobuf。因为底层驱动对数据的采集非常频繁,而且对数据的可读性并没有太高的要求。所以采用序列化体积更小、序列化和反序列化速度更快的protobuf。考虑到后期还会继续深入使用protobuf,先插个眼,方便后期的使用和问题排查。

2. Protobuf 简介

Google Protocol Buffer(简称 Protobuf) 是Google 旗下的一款轻便高效的结构化数据存储格式,平台无关、语言无关、可扩展,可用于通讯协议和数据存储等领域。适合用做数据存储和作为不同应用,不同语言之间相互通信的数据交换格式。

2.1 Protobuf 优点

1.支持多种语言、跨平台,多平台之间只需要维护一套proto协议文件(当然还需要对应的配置)。

2.序列化后是二进制流,体积比Json和Xml小,适合数据量较大的传输场景。

3.序列化和反序列化速度很快,据说比Json和Xml快20~100倍。(ITDragon龙 本地测过,只有在数据达到一定量时才会有明显的差距)

小结:适合传输数据量较大,对响应速度有要求的数据传输场景。

2.2 Protobuf 缺点

1.序列化后的数据不具备可读性。

2.需要一定的额外开发成本(.proto 协议文件),每次修改都需要重新生成协议文件。

3.应用场景并没有Json和Xml广,相对于使用的工具也少。

小结:自解释性较差、通用性较差,不适合用于对基于文本的标记文档建模。

2.3 Protobuf Golang 安装使用

step1:下载protobuf 编译器protoc。下载地址

step2:下载对应的文件。Windows系统直接将解压后的protoc.exe放在GOPATH/bin目录下(该目录要放在环境变量中);Linux系统需要make编译。

step3:安装protobuf库文件(因为protoc并没有直接支持go语言)。官方goprotobuf,执行成功后GOPATH/bin目录下会有protoc-gen-go.exe文件

go get github.com/golang/protobuf/proto
go get github.com/golang/protobuf/protoc-gen-go

据说gogoprotobuf库生成的代码质量和编解码性能都比官方的goprotobuf库强,而且完全兼容官方的protobuf。ITDragon龙 我们当然也不能放过它。

step4:安装gogoprotobuf库文件。执行成功后GOPATH/bin目录下会有protoc-gen-gofast.exe文件

go get github.com/gogo/protobuf/proto
go get github.com/gogo/protobuf/gogoproto
go get github.com/gogo/protobuf/protoc-gen-gofast

step5:使用protoc 生成go文件。先移步到xxx.proto文件所在目录,再执行以下任意一个命令

// 官方goprotobuf
protoc --go_out=. *.proto
// gogoprotobuf
protoc --gofast_out=. *.proto

step6:protoc是直接支持Java语言,下载后可以直接使用。

protoc xxx.proto --java_out=./

3. Protobuf 通讯案例

这里用Golang分别实现socket的服务端和客户端,最后通过protobuf进行数据传输,实现一个简单案例。

3.1 创建.proto协议文件

1.创建一个简单的models.proto协议文件

syntax = "proto3";
package protobuf; message MessageEnvelope{
int32 TargetId = 1;
string ID = 2;
bytes Payload = 3;
string Type = 4;
}

2.通过protoc生成对应的models.pb.go文件(这个文件内容太多,可读性也差,就不贴出来了)

protoc --gofast_out=. *.proto

3.2 protobuf编解码

package protobuf

import (
"fmt"
"github.com/golang/protobuf/proto"
"testing"
) func TestProtocolBuffer(t *testing.T) {
// MessageEnvelope是models.pb.go的结构体
oldData := &MessageEnvelope{
TargetId: 1,
ID: "1",
Type: "2",
Payload: []byte("ITDragon protobuf"),
} data, err := proto.Marshal(oldData)
if err != nil {
fmt.Println("marshal error: ", err.Error())
}
fmt.Println("marshal data : ", data) newData := &MessageEnvelope{}
err = proto.Unmarshal(data, newData)
if err != nil {
fmt.Println("unmarshal err:", err)
}
fmt.Println("unmarshal data : ", newData) }
-----------打印结果-----------
=== RUN TestProtocolBuffer
marshal data : [8 1 18 1 49 26 17 73 84 68 114 97 103 111 110 32 112 114 111 116 111 98 117 102 34 1 50]
unmarshal data : TargetId:1 ID:"1" Payload:"ITDragon protobuf" Type:"2"
--- PASS: TestProtocolBuffer (0.00s)
PASS

3.3 socket通讯

1.TCP Server端

func TestTcpServer(t *testing.T) {
// 为突出重点,忽略err错误判断
addr, _ := net.ResolveTCPAddr("tcp4", "127.0.0.1:9000")
listener, _ := net.ListenTCP("tcp4", addr)
for {
conn, _ := listener.AcceptTCP()
go func() {
for {
buf := make([]byte, 512)
_, _ = conn.Read(buf)
newData := &MessageEnvelope{}
_ = proto.Unmarshal(buf, newData)
fmt.Println("server receive : ", newData)
}
}()
}
}

2.TCP Client端

func TestTcpClient(t *testing.T) {
// 为突出重点,忽略err错误判断
connection, _ := net.Dial("tcp", "127.0.0.1:9000")
var targetID int32 = 1
for {
oldData := &MessageEnvelope{
TargetId: targetID,
ID: strconv.Itoa(int(targetID)),
Type: "2",
Payload: []byte(fmt.Sprintf("ITDragon protoBuf-%d", targetID)),
}
data, _ := proto.Marshal(oldData)
_, _ = connection.Write(data)
fmt.Println("client send : ", data)
time.Sleep(2 * time.Second)
targetID++
}
}

4. Protobuf 基础知识

这里记录工作中常用知识点和对应的注意事项,详细知识点可以通过官网查询:https://developers.google.com/protocol-buffers/docs/proto3

4.1 简单模板

举一个简单列子。不同的编程语言的语法差别主要体现在数据类型的不同。

syntax = "proto3"; 					// 指定使用proto3语法
package protobuf; // 指定包名 message MessageEnvelope{ // 定义一个消息模型
uint32 TargetId = 1; // 定义一个无符号整数类型
string ID = 2; // 定义一个字符串类型
bytes Payload = 3; // 定义一个字节类型
MessageType Type = 4; // 定义一个枚举类型
repeated Player Players = 5; // 定义一个集合对象类型
} enum MessageType { // 定义一个枚举类型
SYSTEM = 0; // 第一个枚举值为零
ALARM = 1;
} message Player {
...
}

4.2 简单语法

1.syntax : 指定使用proto版本的语法,缺省是proto2。若使用syntax语法,则必须位于文件的非空非注释的第一个行。若不指定proto3,却使用了proto3的语法,则会报错。

2.package : 指定包名。防止不同 .proto 项目间命名发生冲突。

3.message : 定义消息类型。

4.enum : 定义枚举类型。第一个枚举值设置为零。

5.repeated : 表示被修饰的变量允许重复,可以理解成集合、数组、切片。

6.map : 待补充

7.Oneof : 待补充

8.定义变量 : (字段修饰符) + 数据类型 + 字段名称 = 唯一的编号标识符;

9.编号标识符 :在message中,每个字段都有唯一的编号标识符。用来在消息的二进制格式中识别各个字段,一旦使用就不能够再改变。[1,15]之内的标识符在编码时占用一个字节。[16,2047]之内的标识符占用2个字节。

10.变量类型:以下来源网络整理

.proto Notes Go Java C++ C# Python
double float64 double double double float
float float32 float float float float
int32 使用变长编码,对于负值的效率很低,如果你的域有可能有负值,请使用sint64替代 int32 int int32 int int
uint32 使用变长编码 uint32 int uint32 uint int/long
uint64 使用变长编码 uint64 long uint64 ulong int/long
sint32 使用变长编码,这些编码在负值时比int32高效的多 int32 int int32 int int
sint64 使用变长编码,有符号的整型值。编码时比通常的int64高效。 int64 long int64 long int/long
fixed32 总是4个字节,如果数值总是比总是比228大的话,这个类型会比uint32高效。 uint32 int uint32 uint int
fixed64 总是8个字节,如果数值总是比总是比256大的话,这个类型会比uint64高效。 uint64 long uint64 ulong int/long
sfixed32 总是4个字节 int32 int int32 int int
sfixed64 总是8个字节 int64 long int64 long int/long
bool bool boolean bool bool bool
string 一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。 string String string string str /unicode
bytes 可能包含任意顺序的字节据。 []byte ByteString string ByteString str

4.3 注意事项

1.整数数据类型区分好有符号和无符号类型,建议少用万金油式的int32。

2.将可能频繁使用的字段设置在[1,15]之内,也要注意预留几个,方便后期添加。

Golang 使用Protocol Buffer 案例的更多相关文章

  1. 使用hessian+protocol buffer+easyUI综合案例--登陆

    首先先简单介绍下hessian ,protocol buffer, easyUI框架 hessian: Hessian是一个轻量级的remoting on http工具,采用的是Binary RPC协 ...

  2. 在 go/golang语言中使用 google Protocol Buffer

    怎么在go语言中实用google protocol Buffer呢? 现在的潮流趋势就是一键搞定,跟ubuntu安装软件一样 go get code.google.com/p/goprotobuf/{ ...

  3. 一看看懂Protocol Buffer(协议篇)

    前言 由于笔者业团队的业务对即时通讯服务有很大的依赖,春节结束后的第一天,红包没到,产品同学先到了,产品同学和我说要做一款IM,看到需求文档后和设计图后笔者大吃一斤 这不就是一个翻版的web qq吗? ...

  4. protocol buffer开发指南(官方)

    欢迎来到protocol buffer的开发者指南文档,一种语言无关.平台无关.扩展性好的用于通信协议.数据存储的结构化数据序列化方法. 本文档是面向计划将protocol buffer使用的到自己的 ...

  5. protocol buffer开发指南

    ProtoBuf 是一套接口描述语言(IDL)和相关工具集(主要是 protoc,基于 C++ 实现),类似 Apache 的 Thrift).用户写好 .proto 描述文件,之后使用 protoc ...

  6. Java与C++进行系统间交互:Protocol Buffer

    在一次项目中,因笔者负责的java端应用需要与公司C++系统进行交互,公司选定Protocol Buffer方案,故简单的了解一下 有需要的可以看一下其他作者的文章,了解一下Protobuf: htt ...

  7. 【转】protocol buffer开发指南

    这个作者的其它golang的文章也值得一读 原文:https://www.cnblogs.com/charlieroro/p/9011900.html protocol buffer开发指南 ---- ...

  8. gRPC in ASP.NET Core 3.x -- Protocol Buffer(2)Go语言的例子(上)

    上一篇文章(大约半年前写的):https://www.cnblogs.com/cgzl/p/11246324.html 建立Go项目 在GOPATH的src下面建立一个文件夹 protobuf-go, ...

  9. Protocol Buffer搭建及示例

    本文来源:http://www.tanhao.me/code/150911.html/ Protocol Buffer(简称Protobuf或PB)是由Google推出的一种数据交换格式,与传统的XM ...

随机推荐

  1. 华为鸿蒙系统pk安卓系统

    Harmony OS Vs Android Comparison It isn’t based on Linux kernel The key difference between HarmonyOS ...

  2. Spring Boot 2.x 整合 Redis最佳实践

    一.前言 在前面的几篇文章中简单的总结了一下Redis相关的知识.本章主要讲解一下 Spring Boot 2.0 整合 Redis.Jedis 和 Lettuce 是 Java 操作 Redis 的 ...

  3. ionic3 发布订阅者模式实现

    在ionic3 中实现订阅发布模式,需要用到Events. Events下面有三个方法 events.subscribe()  订阅 events.publish()  发布 events.unsub ...

  4. 自定义控件 监控宿主activity的生命周期

    使用不显示的fragment来监控activity生命周期,fragment生命周期基本上跟随宿主activity变化.我们通过fragment的生命周期就可以知到activity的生命周期 我们自定 ...

  5. 78)PHP,编写session存储机制(将数据写进数据库)的代码整理(未实验)

    <?php function userSessionBegin() { echo '<br>Begin<br>'; //初始化数据库服务器连接,这个函数是最先执行,所以, ...

  6. SCI|EI|ISTP|万方|istic|NSTL|CASTD|CNKI|nlc|ethesys|CALIS|CETD|proquest|NDLTD|中国科学院学位论文检索系统|学位论文

    BD AC D 三大检索指的是:SCI(科学引文索引 ).EI(工程索引 ).ISTP(科技会议录索引 ) 即Science Citation Index.Engineering Index.Conf ...

  7. hashMap插入初始值

    加了this. 就很容易看出来是使用了内部类和{}代码块 当然也可以把this去掉, 更简洁, 只是不能一眼看出来怎么初始化的 类似的可以做ArrayList ....的初始化

  8. AUTODESK 卸载工具,完美彻底卸载清除干净autodesk各种软件残留注册表和文件

    小伙伴是不是遇到 CAD/3dmax/maya/Revit/Inventor 安装失败或者安装不了的问题了呢?AUTODESK系列软件着实令人头疼,CAD/3dmax/maya/Revit/Inven ...

  9. 浅谈URL重定向

    转载:https://blog.csdn.net/kiyoometal/article/details/90698761 重定向原理 HTTP 协议的重定向响应的状态码为 3xx .浏览器在接收到重定 ...

  10. Java IO: ByteArray和Filter

    作者: Jakob Jenkov 译者: 李璟(jlee381344197@gmail.com) 本小节会简要概括Java IO中字节数组与过滤器的输入输出流,主要涉及以下4个类型的流:ByteArr ...