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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章