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