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