如何处理服务器和客户端中的不同数据包?

时间:2013-07-17 19:53:45

标签: java networking multiplayer packet

在游戏服务器&我计划制作的客户端,从长远来看,我将要处理很多数据包。我想知道如何处理我的不同数据包的最佳做法是什么。

我的数据包有效负载将以PacketID开头。

创建一个扩展Packet的单独类并在那里处理逻辑是不是一个好主意?例如Packet001Login?从长远来看,这将给我一个很多类。

制作巨大的切换声明是否更好?我对此表示怀疑。

这是我没想过的最佳方式吗?

非常感谢任何建议。

1 个答案:

答案 0 :(得分:2)

如果,您确实需要在服务器端进行计算时间,那么您应该采用一种技术来为不同的包类型创建原型。

为了说明这一点和想法,我给你一些像课程描述的UML

UML:

class PacketPrototype
+ PacketPrototype(PacketType)
+ addData(DataType, Bitlength, ...)
+ deserilize(Bitstream stream) : ReceivedPacket
+ serilizeThis() : ToSendPacket
+ getPacketType() : int

你还需要一个包含所有PacketPrototypes的类,并决定每个PacketPrototype对象的Type,应该使用Prototype来对数据进行deserilize。

你需要一个知道每个PacketPrototype的类,我称之为PacketPrototypeHolder

class PacketPrototypeHolder
+ register(PacketPrototype)
+ getPrototypeForPacketType(int Type) : PacketPrototype

关于设置时间的协议如下

PacketEnemy00 = new PacketPrototype(0)
PacketEnemy00.addData(Types.Int, 5) // health
PacketEnemy00.addData(Types.String, 16) // name
...

这意味着类型为0的数据包由一个5位长的int和一个最大长度为16个字符的字符串组成。

我们必须在安装后将PacketPrototype添加到PacketPrototypeHolder

PacketHolder.register(PacketEnemy00)

如果服务器或客户端接收到我们读取数据包类型的内容,那么我们就这样做了 (您可以从比特流中读取数据)

Type = Bitstream.readInt(5)
Prototype = PacketHolder.getPrototypeForPacketType(Type)

ReceivedPacket OfReceivedPacket = Prototype.deserilize(Bitstream)

// we need here a switch/if statement to determine how to handle the reading of the data
switch(Type)
{
  case 0: // PacketEnemy00

Prototype.deserilize调用从数据流读取数据并将其放入ReceivedPacket对象,从那里您可以使用索引操作或命名访问来访问数据。

作为一个例子,我用索引

来做
   int UnitHealth = OfReceivedPacket.getInt(/* index, we want the 1st int */0);
   string UnitName = OfReceivedPacket.getString(/* index, we want the 1st string */0);

   and so on...
   break;
   ...
}

因此,我有效地将switch语句从网络层内部移动到应用程序/使用层。

要删除开关,您需要采用数据驱动方法。但它在引擎中的实现比硬编码方法更复杂。