12.DATA传输协议:协议缓冲区
#go #zinx

[zinx]

<1.Building Basic Services with Zinx Framework>
<2. Zinx-V0.2 Simple Connection Encapsulation and Binding with Business>
<3.Design and Implementation of the Zinx Framework's Routing Module>
<4.Zinx Global Configuration>
<5.Zinx Message Encapsulation Module Design and Implementation>
<6.Design and Implementation of Zinx Multi-Router Mode>
<7. Building Zinx's Read-Write Separation Model>
<8.Zinx Message Queue and Task Worker Pool Design and Implementation>
<9. Zinx Connection Management and Property Setting>

[ZINX应用程序 - MMO游戏案例研究]

<10. Application Case Study using the Zinx Framework>
<11. MMO Online Game AOI Algorithm>
12.Data Transmission Protocol: Protocol Buffers


MMO游戏源代码

https://github.com/aceld/zinx/tree/master/zinx_app_demo/mmo_game


在服务器端项目的当前部分中,使用协议缓冲区表示客户端和服务器之间的通信的数据协议。本节将对协议缓冲区的安装和基本用法提供单独的介绍。如果读者已经熟悉协议缓冲器语法和相关协议,则可以跳过此部分。

12.1协议缓冲区简介

Google协议缓冲区通常称为Protobuf,是由Google开发的轻巧有效的结构化数据存储格式。它是平台 - 敏捷的,语言敏捷的,可扩展的,可用于各种域,例如通信协议和数据存储。这使其适用于不同应用程序的数据存储和使用。它也非常适合不同语言之间的数据交换。通过实现通常在“ .proto”文件中定义的相同协议格式,可以将其编译到不同的语言版本中并集成到各个项目中。这使不同的语言能够使用Protobuf序列化数据。目前,官方网站为C/C ++,Python,Java,Go等语言提供支持。 Google开源协议缓冲区于2008年7月7日。

12.2数据交换格式

ProtoBuf本质上是一种数据交换格式,它是基于应用程序协议构建的数据协议层。这与本书中先前讨论过的TLV协议不同。数据交换格式具有较高的可读性和数据组装功能。但是,权衡是他们的解析性能往往相对较差。 ProtoBuf的设计具有优化,专门针对性能方面。

ProtoBuf的相对优势包括:

(1)序列化导致与JSON和XML相比,数据量较小,使其适用于网络传输。
(2)支持跨平台和多语言用法。
(3)良好的消息格式升级和兼容性。
(4)快速序列化和避免速度,比JSON处理速度快。

ProtoBuf的相对缺点包括:

(1)与XML和JSON相比,采用较少的广泛采用。
(2)二元格式导致可读性较差。
(3)缺乏自我描述。

12.3安装Protobuf环境

本节主要涵盖Linux(Ubuntu)平台上Golang编程语言的Protobuf环境的安装。对于其他操作系统,您可以参考其他资源或官方文档。

12.3.1安装Protobuf编译工具

步骤1:下载Protobuf源代码:

Step 1: Download the Protobuf source code:

另外,您可以直接提取压缩软件包:

unzip protobuf.zip

步骤2:安装所需的库依赖项:

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

步骤3:生成配置配置文件:

cd protobuf/
./autogen.sh

步骤4:配置环境:

./configure

步骤5:编译源代码(此过程可能需要一段时间):

make

步骤6:安装与Protobuf相关的可执行文件:

sudo make install

步骤7:刷新Protobuf要求的动态库。此步骤对于避免动态库路径关联失败至关重要,该失败可能会阻止与Protobuf相关的命令程序开始:

sudo ldconfig

步骤8:通过执行以下命令来测试ProtoBuf是否成功安装了:

protoc -h

如果它显示预期信息而没有任何错误,则该安装成功。

12.3.2安装Protobuf GO语言插件

由于Protobuf不直接支持GO编程语言,因此开发人员需要手动安装相关的插件。

步骤1:获取原始软件包(GO语言的proto api接口)

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

步骤2:编译Golang支持插件的代码

cd $GOPATH/src/github.com/golang/protobuf/protoc-gen-go/
go build

步骤3:放置生成的protoc-gen-go可执行文件

将生成的protoc-gen-go可执行器放入 /bin目录(或任何其他$路径目录)中:

sudo cp protoc-gen-go /bin/

12.4 Protobuf语法

Protobuf通常将用户定义的结构类型称为“消息”。 Protobuf消息的定义通常写在带有“ .proto”扩展名的文件中。

12.4.1一个简单的例子

下面是Protobuf文件的一个示例。您可以将其命名为“ file.proto”。文件的内容如下:

//file.proto

syntax = "proto3";            // Specify version information, an error will occur if not specified
package pb;                   // Package name for generating Go files later

// 'message' is a keyword, used to define a message type
message Person {
    string name = 1;           // Name
    int32 age = 2;              // Age
    repeated string emails = 3; // Email addresses (repeated indicates the field allows duplicates)
    repeated PhoneNumber phones = 4;   // Phone numbers
}

// 'enum' is a keyword, used to define an enumeration type
enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
}

// 'message' is a keyword, used to define a message type that can be nested within another message type
message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
}

原始文件必须具有几个基本元素:

在文件的顶部,需要有一个语法版本信息。在当前的项目示例中,使用的原始版本为“ Proto3”。
软件包声明,指定用于生成GO文件的软件包名称。在使用Golang应用程序的情况下,这通常是相关的。

12.4.2消息格式说明

一条消息由字段组成,消息中每个字段的格式如下:
(字段修改器 +)数据类型 +字段名称 +唯一数字标签

唯一的数字标签,例如Phonenumber中的1和2:

message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
}

代表消息中每个字段的唯一标识符。这些数字标签用于以消息的二进制格式识别字段,并且不能在同一消息中重复。定义消息后,这些标签将无法更改。

12.4.3数据类型

表21-1解释了Protobuf协议支持的数据类型及其在Golang中的相应类型:

表12-1:Protobuf数据类型

更有效编码 ,则比UINT32更有效 ,则比UINT64更有效
.proto type go type 注释
float64 64位浮点数
float float32 32位浮点数
int32 int32 可变长度编码;负效率低下;如果可能的话,请使用sint64进行负值
uint32 uint32 可变长度编码
uint64 uint64 可变长度编码
sint32 int32 可变长度编码;负值比INT32高得多
sint64 int64 可变长度编码;签名整数值;比标准INT64
固定32 uint32 4个字节;如果该值始终大于228
固定64 uint64 8字节;如果该值始终大于256
sfixed32 int32 4个字节
sfixed64 int64 8字节
bool bool 1个字节
字符串 字符串 字符串必须为UTF-8或7位ASCII编码文本
字节 []字节 可能包含字节的任意序列

在上表中,如果您需要在Golang中定义数据类型,则可以参考Proto协议文件中定义的相应的“ .proto类型”。

12.4.4默认值

正在解析消息并且编码信息不包括特定元素时,解析对象中的相应字段设置为默认值。不同的数据类型具有表12-2中指定的默认值:

表12-2:Protobuf默认值

数据类型范围 默认值
字符串类型 默认值是一个空字符串
二进制类型 默认值是一个空字节数组
布尔类型 默认值为false
数字类型 默认值为0

12.5编译Protobuf

您可以使用协议编译器将文件编译为代码,如下所示:

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

在上述命令中,“原始”指令是先前安装的Protobuf协议的编译器。这两个参数定义如下:

(1)--proto_path指定从“ .proto”文件导入软件包的路径。可以指定多个路径。如果被忽略,默认情况下假定当前目录。
(2)--go_out指定了将放置生成的GO语言代码文件的文件夹。

开发人员还可以使用以下方法同时编译多个.proto文件:

protoc --go_out=./ *.proto

在编译期间,Protobuf编译器将从“ .proto”文件中生成“ .pd.go”文件。这些文件不应由开发人员修改。如果需要更改,则应编辑“ .proto”文件,然后重新编译。可以在程序代码中直接导入和引用“ .pd.go”文件。它们包括预定义的数据结构和相关方法。

12.6使用Protobuf协议的Golang编程

在上一节中,Protobuf文件将软件包定义为“ PB”,并且生成的PB文件放在当前路径下的“ protoctbuffer_excise”目录中。现在,您可以编写Golang代码以利用定义的数据协议。代码如下所示:

package main

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

func main() {
    person := &pb.Person{
        Name:   "Aceld",
        Age:    16,
        Emails: []string{"https://github.com/aceld", "https://yuque.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)
}

上面的代码现在可以使用定义的“人”数据协议。 Marshal()方法将内存中的“人”结构编码为序列化的原始数据。 Unmarshal()方法将序列化的二进制数据解析为“人”结构以用于业务代码。


MMO游戏源代码

https://github.com/aceld/zinx/tree/master/zinx_app_demo/mmo_game


[zinx]

<1.Building Basic Services with Zinx Framework>
<2. Zinx-V0.2 Simple Connection Encapsulation and Binding with Business>
<3.Design and Implementation of the Zinx Framework's Routing Module>
<4.Zinx Global Configuration>
<5.Zinx Message Encapsulation Module Design and Implementation>
<6.Design and Implementation of Zinx Multi-Router Mode>
<7. Building Zinx's Read-Write Separation Model>
<8.Zinx Message Queue and Task Worker Pool Design and Implementation>
<9. Zinx Connection Management and Property Setting>

[ZINX应用程序 - MMO游戏案例研究]

<10. Application Case Study using the Zinx Framework>
<11. MMO Online Game AOI Algorithm>
12.Data Transmission Protocol: Protocol Buffers


作者:
不和谐:https://discord.gg/xQ8Xxfyfcz
zinx:https://github.com/aceld/zinx
github:https://github.com/aceld
Aceld的家:https://yuque.com/aceld