Protobuf协议生成和使用

知识点一 利用protoc.exe编译器生成脚本文件

//1.打开cmd窗口

//2.进入protoc.exe所在文件夹(也可以直接将exe文件拖入cmd窗口中)

//3.输入转换指令

//protoc.exe -I=配置路径 --csharp_out=输出路径 配置文件名

//注意:路径不要有中文和特殊符号,避免生成失败

知识点二 测试生成对象是否能使用

cs 复制代码
TestMsg msg = new TestMsg();
        msg.TestBool = true;
        //对应的和List以及Dictionary使用方式一样的 数组和字典对象
        msg.ListInt.Add(1);
        print(msg.ListInt[0]);
        msg.TestMap.Add(1, "DamnF");
        print(msg.TestMap[1]);

        //枚举
        msg.TestEnum = TestEnum.Boss;
        msg.TestEnum2 = TestMsg.Types.TestEnum2.Boss;
        //内部枚举
        msg.TestMsg2 = new TestMsg2();
        msg.TestMsg2.TestInt32 = 99;
        //其他内部类对象
        msg.TestMsg3 = new TestMsg.Types.TestMsg3();
        msg.TestMsg3.TestInt32 = 55;
        //在另一个生成的脚本当中的类 如果命名空间不同 需要命名空间点出来使用
        msg.TestHeart = new GameSystemTest.HeartMsg();

制作ProtobufTool协议生成工具

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using UnityEditor;
using UnityEngine;

public class ProtobufTool
{
    //协议配置文件所在路径
    private static string PROTO_PATH = "C:\\Users\\HONOR\\Desktop\\TeachNet\\Protobuf\\proto";
    //协议生成可执行文件的路径
    private static string PROTOC_PATH = "C:\\Users\\HONOR\\Desktop\\TeachNet\\Protobuf\\protoc.exe";
    //C#文件的生成路径
    private static string CSHARP_PATH = "C:\\Users\\HONOR\\Desktop\\TeachNet\\Protobuf\\csharp";
    //C++文件的生成路径
    private static string CPP_PATH = "C:\\Users\\HONOR\\Desktop\\TeachNet\\Protobuf\\cpp";
    //Java文件的生成路径
    private static string JAVA_PATH = "C:\\Users\\HONOR\\Desktop\\TeachNet\\Protobuf\\java";
    [MenuItem("ProtobufTool/生成C#代码")]
    private static void GenerateCSharp()
    {
        Generate("csharp_out",CSHARP_PATH);
    }
    [MenuItem("ProtobufTool/生成C++代码")]
    private static void GenerateCpp()
    {
        Generate("cpp_out",CPP_PATH);
    }
    [MenuItem("ProtobufTool/生成Java代码")]
    private static void GenerateJava()
    {
        Generate("java_out", JAVA_PATH);
    }
    private static void Generate(string outCmd,string filePath)
    {
        //第一步:遍历对应协议配置文件夹 得到所有的配置文件
        DirectoryInfo directoryInfo = Directory.CreateDirectory(PROTO_PATH);
        //获取对应文件夹下所有文件的信息
        FileInfo[] files = directoryInfo.GetFiles();
        //遍历所有文件 为其生成协议脚本
        for (int i = 0; i < files.Length; i++)
        {
            //后缀的判断 只有是配置文件才能用于生成
            if (files[i].Extension == ".proto")
            {
                //第二步:根据文件内容 来生成对应C#脚本(需要使用C#当中的Process类)
                Process cmd = new Process();
                //protoc.exe的路径
                cmd.StartInfo.FileName = PROTOC_PATH;
                //命令
                cmd.StartInfo.Arguments = $"-I={PROTO_PATH} --{outCmd}={filePath} {files[i]}";
                //执行
                cmd.Start();
                //告诉外部 某一个文件生成结束
                UnityEngine.Debug.Log(files[i] + "生成结束");
            }
        }
        UnityEngine.Debug.Log("所有内容生成结束");
    }
}

Protobuf-Net知识点

//Protobuf的序列化和反序列化都要通过

//流对象来进行处理

//如果是进行本地存储,则可以使用文件流

//如果是进行网络传输,则可以使用内存流获取字节数组

知识点一 序列化存储为本地文件

cs 复制代码
        //主要使用
        //1.生成的类中的 WriteTo方法
        //2.文件流FileStream对象
        TestMsg msg = new TestMsg();
        msg.ListInt.Add(1);
        msg.TestBool = false;
        msg.TestD = 5.5;
        msg.TestInt32 = 99;
        msg.TestMap.Add(1, "DamnF");
        msg.TestMsg2 = new TestMsg2();
        msg.TestMsg2.TestInt32 = 66;
        msg.TestHeart = new GameSystemTest.HeartMsg();
        msg.TestHeart.Time = 7777;
        using (FileStream fs = File.Create(Application.persistentDataPath + "/TestMsg.df"))
        {
            msg.WriteTo(fs);
        }

知识点二 反序列化本地文件

cs 复制代码
       //主要使用
        //1.生成的类中的Parser.ParseFrom方法
        //2.文件流FileStream对象
        using (FileStream fs=File.OpenRead (Application.persistentDataPath + "/TestMsg.df"))
        {
            TestMsg msg2 = null;
            msg2 = TestMsg.Parser.ParseFrom(fs);
            print(msg2.TestMap[1]);
            print(msg2.ListInt[0]);
            print(msg2.TestD);
            print(msg2.TestMsg2.TestInt32);
            print(msg2.TestHeart.Time);
        }

知识点三 得到序列化后的字节数组

cs 复制代码
   //主要使用
        //1.生成的类中的WriteTo方法
        //2.内存流MemoryStream对象
        byte[] bytes = null;
        using (MemoryStream ms=new MemoryStream ())
        {
            msg.WriteTo(ms);
            bytes = ms.ToArray();
            print("字节数组的长度" + bytes.Length);
        }

知识点四 从字节数组反序列化

cs 复制代码
       //主要使用
        //1.生成的类中的 Parser.ParserFrom方法
        //2.内存流MemoryStream对象
        using (MemoryStream ms=new MemoryStream (bytes))
        {
            print("内存流当中反序列化的内容");
            TestMsg msg2 = TestMsg.Parser.ParseFrom(ms);
            print(msg2.TestMap[1]);
            print(msg2.ListInt[0]);
            print(msg2.TestD);
            print(msg2.TestMsg2.TestInt32);
            print(msg2.TestHeart.Time);
        }

封装NetTool

cs 复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Google.Protobuf;
using UnityEngine;

public static class NetTool
{
  public static byte[] GetProtoBytes(IMessage msg)
  {
        //上节课学习的基础写法
        //byte[] bytes = null;
        //using (MemoryStream ms=new MemoryStream())
        //{
        //    msg.WriteTo(ms);
        //    bytes = ms.ToArray();
        //}
        //return bytes;

        //通过该拓展方法,就可以直接获取字节流对象
        return msg.ToByteArray();
  }
  public static T GetProtoMsg<T>(byte[]bytes)where T:class,IMessage
  {
        //得到对应消息的类型 通过反射得到内部的静态成员 然后得到其中对应的方法
        //进行反序列化
        Type type = typeof(T);
        //通过反射 得到对应的 静态成员属性对象
        PropertyInfo pInfp = type.GetProperty("Parser");
        object parseObj= pInfp.GetValue(null, null);
        //已经得到了该对象,那么可以得到该对象中 对应方法
        Type parserType = parseObj.GetType();
        //这是指定得到某一个重载方法
        MethodInfo mInfo = parserType.GetMethod("ParseFrom", new Type[] { typeof(byte[]) });
        //调用对应的方法 反序列化为指定的对象
        object msg= mInfo.Invoke(parseObj, new object[] { bytes });
        return msg as T;
  }
}
相关推荐
淡海水31 分钟前
01-03-认知篇-C#内存模型深度解析
unity·c#·游戏引擎·.net·gc
梦帮科技3 小时前
领域认知知识库图谱注入:从双式记账图网络到高质量问答对自动化合成流水线
运维·网络·数据库·人工智能·矩阵·架构·自动化
菜鸡养成中...4 小时前
卫星通信协议笔记1-协议栈
网络
hzxpaipai4 小时前
杭州企业官网怎么建设?从策划到上线的5步建站方法
运维·服务器·前端·网络
smartpi_ai4 小时前
通用脱机烧录器为什么烧不进 CI-03?下载协议的门槛、免唤醒 10 条的建议值属性
服务器·网络·ci/cd
ITxiaobing20235 小时前
自研 IP 库与 AppsFlyer 判定不一致的排查实践
网络·网络协议·tcp/ip
2501_937860946 小时前
中篇:TCP 为什么可靠又高效?滑动窗口、流量控制、拥塞控制与粘包全解析
服务器·网络·tcp/ip
lzhdim6 小时前
C#不为人知的10个魔法特性:资深开发者也会震惊的底层奥秘
java·前端·javascript·算法·c#
刚及格的陆拾伍6 小时前
Wi-Fi核心知识精要:从频段到帧结构全解析
网络·物联网·网络协议·信息与通信·iot
xiaoye-duck7 小时前
《Linux 网络编程》深入理解 IO 多路复用:select 函数详解与 Echo 服务实战
linux·网络