当前位置: 代码迷 >> 综合 >> 【Protobuf】Protobuf协议
  详细解决方案

【Protobuf】Protobuf协议

热度:35   发布时间:2023-11-22 18:24:12.0

Protobuf协议

    • 什么是Protobuf
      • 一、编写proto文件
      • 二、生成协议类
      • 三、编码解码
        • 3.1 编码方法
        • 3.2 解码方法

什么是Protobuf

Protobuf是谷歌发布的一套协议格式,它规定了一系列编码和解码方法。

目前,网上已经有不少实现Protobuf编码解码的库,可以直接使用。Protobuf协议的一大特点是编码后的数据量较小,可以节省网络带宽。

使用Protobuf协议的使用流程:

  1. 编写描述文件(即.proto文件)
  2. 安装第三方工具,这个工具可以根据描述文件(即.proto文件)自动生成协议类,协议类里面除了成员属性外,还包含编码解码所需的一些信息。
  3. 调用第三方库函数,将协议对象编码成byte数组。
    请添加图片描述

一、编写proto文件

例:BattleMsg.proto

message MsgMove {optional int32 x = 1;optional int32 y = 2;optional int32 z = 3;
}

二、生成协议类

Protobuf-net是一套开源的第三方库,它不仅提供了将Protobuf描述文件转换成协议类的工具,还实现了协议对象编码解码的方法。不少Unity游戏使用Protobuf-net处理Protobuf协议。

  1. 下载protobuf-net,并且编译
https://github.com/mgravell/protobuf-net
  1. 设置目录
    打开编译好的protobuf-net目录,会看到里面有两个文件夹。proto文件夹是存放proto文件的地方,需要将前面写好的proto文件放进入。cs文件夹为生成出的协议类存放目录。run.bat是一个批处理文件,可以用记事本打开,里面记录需要生成的文件和路径,设置正确的文件和目录才能生成协议。run.bat的内容如下:
protogen.exe -i:proto\BattleMsg.proto -o:cs\BattleMsg.cs
pause
  1. 生成协议类
    将proto文件存放到proto目录下,修改run.bat之后,双击run.bat运行它,程序会生成协议类文件,并存放到cs目录下。

    打开BattleMsg.cs,能够看到如下的协议类。除了成员desc外,协议类还附带了编码解码所需要的一些信息。MsgAttack继承自global::ProtoBuf.IExtensible。使用Protobuf协议,可将global::ProtoBuf.IExtensible当作协议基类。

[global::System.Serializable, global::ProtoBuf.ProtoContract(Name=@"MsgAttack")]
public partial class MsgAttack : global::ProtoBuf.IExtensible
{public MsgAttack() {}private string _desc = "";[global::ProtoBuf.ProtoMember(1, IsRequired = false, Name=@"desc", DataFormat = global::ProtoBuf.DataFormat.Default)][global::System.ComponentModel.DefaultValue("")]public string desc{get { return _desc; }set { _desc = value; }}private global::ProtoBuf.IExtension extensionObject;global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing){return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing);}
} 
  1. 将协议文件复制到游戏工程

将生成出来的BattleMsg.cs放入游戏工程Script/proto目录下,放入后游戏不能运行,会有一些报错。这是因为生成的文件引用了ProtoBuf.ProtoMember和ProtoBuf.Extensible等类型,它在protobuf-net的库文件中定义,需要把protobuf-net的库文件引入到游戏项目中。

protobuf-net.dll是protobuf-net的库文件,可以在编译好的目录中找到它,将它复制到游戏工程的任一目录中。

三、编码解码

3.1 编码方法

编码方法Encode如下所示。它接收ProtoBuf.IExtensible类型的协议基类,然后调用ProtoBuf.Serializer.Serialize将协议对象转化为字节流。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using proto.BattleMsg;public class testProto : MonoBehaviour {//将protobuf对象序列化为Byte数组public static byte[] Encode(ProtoBuf.IExtensible.msgBase){using (var memory = new System.IO.MemoryStream()){ProtoBuf.Serializer.Serialize(memory, msgBase); return memory.ToArray();}}//Use this for initializationvoid Start() {//Protobuf测试MsgMove msgMove = new MsgMove();msgMove.x = 214;byte[] bs = Encode(msgMove);	//将protobuf对象序列化为Byte数组Debug.Log(System.BitConverter.ToString(bs));}
}

3.2 解码方法

解码方法Decode如下所示。第一个参数protoName代表协议协议名称,第二个参数代表要解码的byte数组,第三和第四参数代表协议体数据所在的起始位置和长度。

程序使用ProtoBuf.Serializer.NonGeneric.Deserialize解码Protobuf数据,并将它转换成基于Protobuf协议基类ProtoBuf.IExtensible的对象返回。

public static ProtoBuf.IExtensible Decode(string protoName, byte[] bytes, int offset, int count)
{using(var memory = new System.IO.MemoryStream(bytes, offset, count)){System.Type t = System.Type.GetType(protoName);return (ProtoBuf.IExtensible)ProtoBuf.Serializer.NonGeneric.Deserialize(t, memory);}
}
  相关解决方案