在我计划制作的游戏服务器和客户端中,从长远来看,我必须处理很多数据包。我想知道如何处理我的不同数据包的最佳实践是什么。
我的数据包有效负载将以 PacketID 开头。
创建一个扩展 Packet 的单独类并处理其中的逻辑是个好主意吗?例如Packet001Login?从长远来看,这会给我带来很多类(class)。
制作一个巨大 switch 语句是否更好?我对此表示怀疑。
最好的方法是我没有想到的吗?
非常感谢任何建议。
最佳答案
如果您在服务器端确实有足够的计算时间,您应该研究一种为不同包类型创建原型(prototype)的技术。
为了说明这一点和想法,我给你一些类似于类描述的 UML
UML:
class PacketPrototype
+ PacketPrototype(PacketType)
+ addData(DataType, Bitlength, ...)
+ deserilize(Bitstream stream) : ReceivedPacket
+ serilizeThis() : ToSendPacket
+ getPacketType() : int
您还需要一个包含所有 PacketPrototype 的类,并决定每个 PacketPrototype 对象的类型,应使用哪个 Prototype 来反序列化数据。
你需要一个知道每个 PacketPrototype 的类,我称之为 PacketPrototypeHolder
class PacketPrototypeHolder
+ register(PacketPrototype)
+ getPrototypeForPacketType(int Type) : PacketPrototype
建立时间协议(protocol)如下
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)
如果服务器或客户端收到我们读取的数据包类型,那么我们就会这样做 (您可以从Bitstream读取数据)
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 语句从网络层内部移至应用程序/使用层。
要删除开关,您需要采用数据驱动的方法。但它在引擎中的实现比硬编码的方法更复杂。
关于java - 如何处理服务器和客户端中不同的数据包?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17709666/