【Zinx应用-MMO游戏案例-(3)数据传输协议protocol buffer】Golang轻量级并发服务器框架

Zinx源代码

github
https://github.com/aceld/zinx
gitee码云
https://gitee.com/Aceld/zinx


在线开发教程

【B站】
zinx视频教程-Golang轻量级TCP服务器框架-适合自学者

【YouTube】
zinx开发YouTube中国版

微信端文档

【Zinx应用-MMO游戏案例-(3)数据传输协议protocol buffer】Golang轻量级并发服务器框架_第1张图片
技术资源分享.jpg

【Zinx教程目录】
完整教程电子版(在线高清)-下载
Zinx框架视频教程(框架篇)(完整版下载)链接在下面正文
Zinx框架视频教程(应用篇)(完整版下载)链接在下面正文
Zinx开发API文档
Zinx第一章-引言
Zinx第二章-初识Zinx框架
Zinx第三章-基础路由模块
Zinx第四章-全局配置
Zinx第五章-消息封装
Zinx第六章-多路由模式
Zinx第七章-读写分离模型
Zinx第八章-消息队列及多任务
Zinx第九章-链接管理
Zinx第十章-连接属性设置


【Zinx应用案例-MMO多人在线游戏】
(1)案例介绍
(2)AOI兴趣点算法
(3)数据传输协议protocol buffer
(4)Proto3协议定义
(5)构建项目及用户上线
(6)世界聊天
(7)上线位置信息同步
(8)移动位置与AOI广播
(9)玩家下线
(10)模拟客户端AI模块


四、数据传输协议protocol buffer

4.1 简介

Google Protocol Buffer (简称 Protobuf)是google旗下的一款轻便高效的结构化数据存储格式,平台无关、语言无关、可扩展,可用于通讯协议和数据存储等领域。所以很适合用做数据存储和作为不同应用,不同语言之间相互通信的数据交换格式,只要实现相同的协议格式即同一 proto文件被编译成不同的语言版本,加入到各自的工程中去。这样不同语言就可以解析其他语言通过 protobuf序列化的数据。目前官网提供了 C++,Python,JAVA,GO等语言的支持。google在2008年7月7号将其作为开源项目对外公布。

tips:

  1. 啥叫平台无关?Linux、mac和Windows都可以用,32位系统,64位系统通吃
  2. 啥叫语言无关?C++、Java、Python、Golang语言编写的程序都可以用,而且可以相互通信
  3. 那啥叫可扩展呢?就是这个数据格式可以方便的增删一部分字段啦~
  4. 最后,啥叫序列化啊?解释得通俗点儿就是把复杂的结构体数据按照一定的规则编码成一个字节切片

4.2 数据交换格式

A)常用的数据交换格式有三种:

  1. json: 一般的web项目中,最流行的主要还是 json。因为浏览器对于json 数据支持非常好,有很多内建的函数支持。
  2. xml: 在 webservice 中应用最为广泛,但是相比于 json,它的数据更加冗余,因为需要成对的闭合标签。json 使用了键值对的方式,不仅压缩了一定的数据空间,同时也具有可读性。
  3. protobuf: 是后起之秀,是谷歌开源的一种数据格式,适合高性能,对响应速度有要求的数据传输场景。因为 profobuf 是二进制数据格式,需要编码和解码。数据本身不具有可读性。因此只能反序列化之后得到真正可读的数据。

B)protobuf的优势与劣势

优势:

1:序列化后体积相比Json和XML很小,适合网络传输

2:支持跨平台多语言

3:消息格式升级和兼容性还不错

4:序列化反序列化速度很快,快于Json的处理速速

劣势:

1:应用不够广(相比xml和json)

2:二进制格式导致可读性差

3:缺乏自描述


4.3 protobuf环境安装

A) protobuf 编译工具安装

1、下载 protoBuf:

cd $GOPATH/src/
git clone https://github.com/protocolbuffers/protobuf.git

2、或者直接将压缩包拖入后解压

unzip protobuf.zip 

3、安装依赖库

sudo apt-get install autoconf  automake  libtool curl make  g++  unzip libffi-dev -y

4、进入目录

cd protobuf/ 

5、自动生成configure配置文件:

./autogen.sh 

6、配置环境:

./configure

7、编译源代码(时间比较长):

make 

8、安装

sudo make install

9、刷新共享库 (很重要的一步啊)

sudo ldconfig 

10、成功后需要使用命令测试

protoc -h  

由于protobuf并没直接支持go语言需要我们手动安装相关插件

B) protobuf 的 go 语言插件安装
  1. 获取 proto包(Go语言的proto API接口)
go get  -v -u github.com/golang/protobuf/proto
go get  -v -u github.com/golang/protobuf/protoc-gen-go
  1. 编译
cd $GOPATH/src/github.com/golang/protobuf/protoc-gen-go/
go build
  1. 将生成的 protoc-gen-go可执行文件,放在/bin目录下
sudo cp protoc-gen-go /bin/

4.4 protobuf语法

protobuf 通常会把用户定义的结构体类型叫做一个消息,这里我们遵循惯例,统一称为消息。protobuf 消息的定义(或者称为描述)通常都写在一个以 .proto 结尾的文件中。

A) 一个简单的例子
syntax = "proto3";                      //指定版本信息,不指定会报错
package pb;                     //后期生成go文件的包名

//message为关键字,作用为定义一种消息类型
message Person {
    string  name = 1;                   //姓名
    int32   age = 2;                    //年龄
    repeated string emails = 3;         //电子邮件(repeated表示字段允许重复)
    repeated PhoneNumber phones = 4;    //手机号
}

//enum为关键字,作用为定义一种枚举类型
enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
}

//message为关键字,作用为定义一种消息类型可以被另外的消息类型嵌套使用
message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
}
B) 消息格式说明

消息由字段组成,每个消息的字段格式为:

(字段修饰符 +)数据类型 + 字段名称 + 唯一的编号标签值;

  • 字段名称:蛇形或者驼峰

  • 唯一的编号标签:代表每个字段的一个唯一的编号标签,在同一个消息里不可以重复。这些编号标签用与在消息二进制格式中标识你的字段,并且消息一旦定义就不能更改。需要说明的是标签在1到15范围的采用一个字节进行编码,所以通常将标签1到15用于频繁发生的消息字段。编号标签大小的范围是1到229

  • 注释格式:向.proto文件添加注释,可以使用C/C++/java/Go风格的双斜杠(//) 语法格式

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

更多详情请看:https://developers.google.com/protocol-buffers/docs/encoding

D) 默认缺省值

当一个消息被解析的时候,如果被编码的信息不包含一个特定的元素,被解析的对象锁对应的域被设置位一个默认值,对于不同类型指定如下:

  • 对于strings,默认是一个空string
  • 对于bytes,默认是一个空的bytes
  • 对于bools,默认是false
  • 对于数值类型,默认是0

4.5 编译protobuf

通过如下方式调用protocol编译器,把 .proto 文件编译成代码:

 protoc --proto_path=IMPORT_PATH --go_out=DST_DIR path/to/file.proto

其中:

  1. --proto_path,指定了 .proto 文件导包时的路径,可以有多个,如果忽略则默认当前目录。
  2. --go_out, 指定了生成的go语言代码文件放入的文件夹
  3. 允许使用 protoc --go_out=./ *.proto 的方式一次性编译多个 .proto 文件
  4. 编译时,protobuf 编译器会把 .proto 文件编译成 .pd.go 文件

4.6 利用protobuf生成的类来编码

package main

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

func main() {
    person := &pb.Person{
        Name:   "Aceld",
        Age:    16,
        Emails: []string{"https://legacy.gitbook.com/@aceld", "https://github.com/aceld"},
        Phones: []*pb.PhoneNumber{
            &pb.PhoneNumber{
                Number: "13113111311",
                Type:   pb.PhoneType_MOBILE,
            },
            &pb.PhoneNumber{
                Number: "14141444144",
                Type:   pb.PhoneType_HOME,
            },
            &pb.PhoneNumber{
                Number: "19191919191",
                Type:   pb.PhoneType_WORK,
            },
        },
    }

    data, err := proto.Marshal(person)
    if err != nil {
        fmt.Println("marshal err:", err)
    }

    newdata := &pb.Person{}
    err = proto.Unmarshal(data, newdata)
    if err != nil {
        fmt.Println("unmarshal err:", err)
    }

    fmt.Println(newdata)
}

关于作者:

作者:Aceld(刘丹冰)
号:IT无崖子

mail: [email protected]
github: https://github.com/aceld
原创书籍gitbook: http://legacy.gitbook.com/@aceld

原创声明:未经作者允许请勿转载, 如果转载请注明出处

你可能感兴趣的:(【Zinx应用-MMO游戏案例-(3)数据传输协议protocol buffer】Golang轻量级并发服务器框架)