Lidgren的通用包系统

时间:2014-08-04 09:34:27

标签: c# .net lidgren

我使用Lidgren.Networking在客户端/服务器架构中的服务器和客户端之间发送数据。我创建了一个Packet类,用于通过网络发送数据包。

Packet.cs

public abstract class Packet : IPackable
{
    public abstract void PackIntoNetMessage(NetOutgoingMessage msg);
    public abstract void PopulateFromNetMessage(NetIncomingMessage msg);
}

IPackable.cs

interface IPackable
{
    void PackIntoNetMessage(NetOutgoingMessage msg);
    void PopulateFromNetMessage(NetIncomingMessage msg);
}

然后我有像这样的应用程序特定的数据包类

public class PositionPacket : Packet
{
    public int PosX { get; set; }
    public int PosY { get; set; }

    public override void PackIntoNetMessage(NetOutgoingMessage m)
    {
        m.Write((byte)Networking.PacketTypes.PositionPacket);
        m.Write(PosX);
        m.Write(PosY);
    }

    public override void PopulateFromNetMessage(NetIncomingMessage m)
    {
        PosX = m.ReadInt32();
        PosY = m.ReadInt32();
    }
}

发送数据包很简单,我只需创建一个数据包和PackIntoNetMessage(msg)然后发送它。但是当我尝试接收数据包时,我遇到了一些恼人的结构问题。

我首先阅读第一个字节

var packetType = (Networking.PacketTypes)incomingMsg.ReadByte();

然后我必须为每个数据包类型做一个开关,以便获得正确的构造函数。

switch (packetType)
{
    case Networking.PacketTypes.PositionPacket:
        incPacket = new Packets.PositionPacket();
        break;
    default:
        incPacket = null;
        break;
}
//Populate packet from net message
incPacket.PopulateFromNetMessage(incomingMsg);

这是我不喜欢的部分。我希望能够创建一个通用的数据包处理系统来处理从Packet派生的任何类。我想反射不会是一个好主意,因为它会杀死性能。我该如何构建它以使其更通用?

1 个答案:

答案 0 :(得分:2)

需要以某种方式创建特定类的实例,以便您可以在启动时使用反射来填充字典,其中包含从其ID存储的数据包派生的所有可用类。

创建一个实例然后归结为:

var packetTypeId = (Networking.PacketTypes)incomingMsg.ReadByte();
var incPackage = (Package)Activator.CreateInstance(packetTypes[packetTypeId]);

如果您担心创建许多实例并且期望垃圾收集周期对您的应用程序的速度有很大影响,您可以创建一个回收实例的对象池。只要将不再使用的对象放回池中,就可以防止GC循环。

var packetTypeId = (Networking.PacketTypes)incomingMsg.ReadByte();
Type packetType = packetTypes[packetTypeId];
Package incPackage;
if(!pool.TryGetRecycledInstance(packetType, out incPackage))
{
    incPackage = (Package)Activator.CreateInstance(packetType);
}