protobuf-net 的应用

protobuf-net 的应用

https://blog.csdn.net/st02009/article/details/78742483?utm_source=blogxgwz7

protobuf-net 通常用于数据传输和excel数据的二进制化,是一个方便的工具
现在写一个关于协议的protobuf-net的应用

**
0先将自动化的cmd代码贴出来

**

set CSC20=C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe
SET PROTO=protobuf\

mkdir proto
rmdir /s/q proto-build\code
mkdir proto-build\code
rmdir /s/q proto-build\dll
mkdir proto-build\dll

pushd proto

set protogenexe=..\protogen\protogen.exe

for %%p in (*.proto) do %protogenexe% -i:%%p -o:..\proto-build\code\%%~np.cs -ns:sg
popd

set proto_dll=proto-build\dll\mymodel.dll
%CSC20% /target:library /out:%proto_dll% /reference:protogen\protobuf-net.dll proto-build\code*.cs
serializer\serializer-builder.exe %cd%\%proto_dll% 70 proto-final\

pause
1首先获取protobuf-net,这个网上不少,获取一个
2自己编写协议的格式,用txt,最后改后缀为proto,

例子如下:
//副本列表请求
message Copy_List_Req{
required int32 roleID = 1; //玩家ID
required int32 battleID = 2; //战役ID
}
3用protogen.exe 将2的文本协议转化成对应的cs文件,具体代码是(这是一个批处理针对多个proto文本文件)

“`
set protogenexe=..\protogen\protogen.exe
for %%p in (*.proto) do %protogenexe% -i:%%p -o:..\proto-build\code\%%~np.cs -ns:sg


4,将上面生成的所有cs文件转换成一个dll文件
------------------------

    1
    2
    3
    4

set proto_dll=proto-build\dll\mymodel.dll
%CSC20% /target:library /out:%proto_dll% /reference:protogen\protobuf-net.dll proto-build\code*.cs

5,

**

将上面生成的dll文件序列化成二进制且每70个proto分割成一个新的dll,cmd里对应的代码是
-------------------------------------------------

**

 serializer\serializer-builder.exe %cd%\%proto_dll% 70 proto-final\

    其中 serialize代码是

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

using System;
using System.IO;

namespace mw_serializer_builder
{
class Program
{

    static void Main(string[] args)
    {
        string path = args[0];

        Console.WriteLine(path);

        FileInfo info = new FileInfo(path);
        string modelFileName = Path.GetFileNameWithoutExtension(path);

        var ass = System.Reflection.Assembly.LoadFile(path);

        var types = ass.GetTypes();

        var tm = ProtoBuf.Meta.TypeModel.Create();

        int split = int.Parse(args[1]);
        string outPath = args[2];
        int c = 0;
        int i = 0;
        foreach(var t in types)
        {
            if(t.Name.EndsWith("_ValidateInfo"))
            {
                continue;
            }

            tm.Add(t, true);

            i++;
            if (i > split)
            {
                string serializens = modelFileName + "-serializer-" + c.ToString();
                string serializername = serializens + ".dll";
                tm.Compile(serializens.Replace("-", "_"), serializername );
                File.Copy(serializername  ,outPath + serializername,true);
                File.Delete(serializername  );
                Console.WriteLine(serializername);
                c++;
                tm = ProtoBuf.Meta.TypeModel.Create();
                i = 0;
            }
        }

        if (i > 0)
        {
            string serializens = modelFileName + "-serializer-" + c.ToString();
            string serializername = serializens + ".dll";
            tm.Compile(serializens.Replace("-", "_"), serializername);
            File.Copy(serializername  , outPath + serializername,true);
            File.Delete(serializername );
            Console.WriteLine(serializername);
        }
    }
}

    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

}

6.上面的一切是为了解析从服务器发来的数据,一般服务器的发来的二进制数据前一个或2个字节解析出来的整数经过客户端事先存好的映射关系取得type,就是反序列化需要的类的类型获得最终可用的结构
代码如下

    1
    2
    3
    4

static Packet Parse(int pt, Stream stm)
{

  if (pt == (int)PacketTypeS2C.LS2C_LOGIN)
      {
          mw.LoginReturn lr = m_serializer.Deserialize(stm, null, typeof(mw.LoginReturn)) as mw.LoginReturn;
          return new Packet(pt, lr);
      }
    .......
    .......
}

    1
    2
    3
    4
    5
    6
    7
    8

在实例化协议类的时候可以加上特性custom attribute,然后写一个方法统一处理这些特性如`[PacketHandlerAttribute(PacketOpcode.CHANNEL_AND_VERSION_REQ,typeof(sg.LS2C_Channel_And_Version_Res))]
    public void RequestCheckChannelAndVersion(string channelId,string versionNum,NetManager.RevCallBackWithPacket del) {
        Packet pak = new Packet();
        sg.C2LS_Channel_And_Version_Req req = new sg.C2LS_Channel_And_Version_Req();
        req.channelId = channelId;
        req.versionNum = versionNum;
        pak.data = req;
        pak.opcode = PacketOpcode.CHANNEL_AND_VERSION_REQ;
        LSNetManager.Instance.SendPacket(pak,del);
    }`
 统一管理的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

protected void RegisterPacketHandler(object obj) {
var methods = obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);
foreach(var method in methods) {
PacketHandlerAttribute[] attributes = method.GetCustomAttributes(typeof(PacketHandlerAttribute),false) as PacketHandlerAttribute[];
if(attributes.Length == 0)
continue;
try {
foreach(var attribute in attributes) {
if(obj is NetReceiver) {
var handlerDelegate = (HandlePacketDelegate)Delegate.CreateDelegate(typeof(HandlePacketDelegate),obj,method);
RegisterReceiveDelegate(attribute.PacketOpcodeID,handlerDelegate);
}
if(!packetReflections.ContainsKey(attribute.PacketOpcodeID)) {
packetReflections.Add(attribute.PacketOpcodeID,attribute.HandlerType);
}
}
} catch(Exception e) {
var handlerStr = obj.GetType().FullName + “.” + method.Name;
throw new Exception(“Unable to register PacketHandler ” + handlerStr + “.\n” + e.Message);
}
}
}
“`这样通过数字转换成enum,通过enum对应type,通过type用上面的已经二进制化的dll反序列化二进制获取object

发送数据的时候就简单了,直接序列化就好了
————————————————
版权声明:本文为CSDN博主「st02009」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/st02009/article/details/78742483

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值