Универсальная система пакетов для 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 ответ

Решение

Экземпляр определенного класса должен быть каким-то образом создан, чтобы вы могли использовать отражение при запуске, чтобы заполнить словарь всеми доступными классами, которые являются производными от Packet, сохраненными по их идентификаторам.

Создание экземпляра будет затем сводиться к:

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);
}
Другие вопросы по тегам