• Unity C# 网络学习(十二)——Protobuf生成协议


    Unity C# 网络学习(十二)——Protobuf生成协议

    一.安装

    • Protobuf官网下载对应操作系统的protoc,用于将.proto文件生成对应语言的协议语言文件在这里插入图片描述
    • 由于我使用的是C#所以可以使用提供的C#的序列化反序列化的项目,然后自己编译出DLL放入Unity中使用
      在这里插入图片描述

    二.Protobuf 配置的规则(.proto文件的语法)

    syntax = "proto3";//决定了proto文档的版本号
    package GamePlayerTest;//命名空间
    
    import "test2.proto";
    
    //消息类
    message TestMsg1 {
        //成员类型 成员名称 唯一编号
        
        //浮点数
        float testF = 1;
        double testD = 2;
        //变长编码
        //Protobuf会自动优化,可以尽量少的使用字节数,来存储内容
        int32 testInt32 = 3;  //不太适用于负数
        int64 testInt64 = 4;
        
        //更适用于负数
        sint32 testSInt32 = 5;
        sint64 testSInt64 = 6;
        
        //无符号变长编码
        uint32 testUInt32 = 7;
        uint64 testUInt64 = 8;
        
        //固定字节数类型
        fixed32 testFixed32 = 9; //通常用于表示大于2的28次方的数 uint
        fixed64 testFixed64 = 10; //通常用于表示大于2的56次方的数 ulong
        
        sfixed32 testSFixed32 = 11; //int
        sfixed64 testSFixed64 = 12; //long
        
        //数组
        repeated int32 arr_int32 = 13;
        repeated string arr_string = 14;
        //字典
        map<int32,string> map1 = 15;
        //枚举
        TestEnum1 test_enum1 = 16;
        
        //嵌套消息
        message TestMsg2{
            int32 test_int32 = 1;
        }
        
        TestMsg2 test_msg2 = 17;
        //嵌套枚举
        enum TestEnum2{
            NORMAL = 0;
            BOSS = 1;
        }
        
        TestEnum2 test_enum2 = 18;
    
        GameSystemTest.HeartMsg heart_msg = 19;
    }
    
    enum TestEnum1{
        NORMAL = 0;
        BOSS = 5;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    syntax = "proto3";
    package GameSystemTest;
    
    message HeartMsg{
        int64 time = 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    三.生成对应的C#代码

    • 打开cmd窗口
    • 进入protoc.exe所在文件夹(也可以直接拖入到cmd中)
    • 输入转换指令
    • protoc.exe -I=配置路径 =csharp_out=输出路径 配置文件名

    四.封装快捷生成协议文件

    public static class GenerateProtobuf
    {
        private const string ProtocPathExe = @"D:\Unity_Project\AgainLearnNet\Protobuf\protoc.exe";
        private const string ProtoPath = @"D:\Unity_Project\AgainLearnNet\Protobuf\proto";
        private const string OutPath = @"D:\Unity_Project\AgainLearnNet\Protobuf\csharp";
        [MenuItem("Protobuf/GenerateCSharp")]
        private static void GenerateCSharp()
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(ProtoPath);
            FileInfo[] fileInfos = directoryInfo.GetFiles();
            foreach (var fileInfo in fileInfos)
            {
                if(fileInfo.Extension != ".proto")
                    continue;
                Process cmd = new Process();
                cmd.StartInfo.FileName = ProtocPathExe;
                cmd.StartInfo.Arguments = $"-I={ProtoPath} --csharp_out={OutPath} {fileInfo.Name}";
    
                cmd.Start();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    五.协议的序列化和反序列化

    1.文本流

        private void Start()
        {
            MyTestMsg myTestMsg = new MyTestMsg();
            myTestMsg.PlayerId = 1;
            myTestMsg.Name = "zzs";
            myTestMsg.Friends.Add("wy");
            myTestMsg.Friends.Add("pnb");
            myTestMsg.Friends.Add("lzq");
            myTestMsg.Map.Add(1,"ywj");
            myTestMsg.Map.Add(2,"zzs");
    
            string path = Application.persistentDataPath + "/testMsg.msg";
            using (FileStream fs = new FileStream(path,FileMode.Create))
            {
                myTestMsg.WriteTo(fs);
            }
    
            MyTestMsg newMyTestMsg;
            using (FileStream fs = new FileStream(path,FileMode.Open))
            {
                newMyTestMsg = MyTestMsg.Parser.ParseFrom(fs);
            }
            Debug.Log(newMyTestMsg.PlayerId);
            Debug.Log(newMyTestMsg.Name);
            Debug.Log(newMyTestMsg.Friends.Count);
            Debug.Log(newMyTestMsg.Map[1]);
            Debug.Log(newMyTestMsg.Map[2]);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    2.内存流

        private void Start()
        {
            MyTestMsg myTestMsg = new MyTestMsg
            {
                PlayerId = 1,
                Name = "zzs"
            };
            myTestMsg.Friends.Add("wy");
            myTestMsg.Friends.Add("pnb");
            myTestMsg.Friends.Add("lzq");
            myTestMsg.Map.Add(1,"ywj");
            myTestMsg.Map.Add(2,"zzs");
    
            byte[] buffer;
            using (MemoryStream ms = new MemoryStream())
            {
                myTestMsg.WriteTo(ms);
                buffer = ms.ToArray();
            }
    
            MyTestMsg newMyTestMsg;
            using (MemoryStream ms = new MemoryStream(buffer))
            {
                newMyTestMsg = MyTestMsg.Parser.ParseFrom(ms);
            }
            Debug.Log(newMyTestMsg.PlayerId);
            Debug.Log(newMyTestMsg.Name);
            Debug.Log(newMyTestMsg.Friends.Count);
            Debug.Log(newMyTestMsg.Map[1]);
            Debug.Log(newMyTestMsg.Map[2]);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    六.Protobuf的序列化和反序列化(优化调用方式)

        private void Start()
        {
            MyTestMsg myTestMsg = new MyTestMsg
            {
                PlayerId = 1,
                Name = "zzs"
            };
            myTestMsg.Friends.Add("wy");
            myTestMsg.Friends.Add("pnb");
            myTestMsg.Friends.Add("lzq");
            myTestMsg.Map.Add(1,"ywj");
            myTestMsg.Map.Add(2,"zzs");
            
            
            byte[] buffer = myTestMsg.ToByteArray();
            MyTestMsg newMyTestMsg = MyTestMsg.Parser.ParseFrom(buffer);
            
            
            Debug.Log(newMyTestMsg.PlayerId);
            Debug.Log(newMyTestMsg.Name);
            Debug.Log(newMyTestMsg.Friends.Count);
            Debug.Log(newMyTestMsg.Map[1]);
            Debug.Log(newMyTestMsg.Map[2]);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
  • 相关阅读:
    好用的思维导图软件Xmind Pro 中文专业安装
    Go语言 错误处理
    关于俄罗斯游戏玩家特征的几个事实
    Linux02-常规使用和命令
    基于SSM的共享客栈管理系统的设计与实现
    【面试题】JS 常见的 6 种继承方式(常见)
    【Python21天学习挑战赛】-入门必备
    计算机四级网络-网络技术-第六章 网络管理与网络安全
    六大维度全景呈现:《数据安全法》实施一周年行业洞察
    7种系统设计中的数据库范式
  • 原文地址:https://blog.csdn.net/zzzsss123333/article/details/125505066