【问题标题】:How to handle the different packets in both the server and client?如何处理服务器和客户端中的不同数据包?
【发布时间】:2013-07-17 19:53:44
【问题描述】:

在我计划制作的游戏服务器和客户端中,从长远来看,我需要处理大量的数据包。我想知道如何处理我的不同数据包的最佳实践是什么。

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

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

做一个巨大的 switch 语句会更好吗?我怀疑。

最好的方法是我没想到的吗?

非常感谢任何建议。

【问题讨论】:

    标签: java networking multiplayer packet


    【解决方案1】:

    如果您在服务器端确实有足够的计算时间,您应该研究一种技术来为不同的包类型创建原型。

    为了说明这一点和想法,我给你一些类似 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
    

    设置时间协议如下

    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 语句从网络层内部移动到了应用程序/使用层。

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

    【讨论】:

    • 嗯。我不太明白。能否提供更多细节或示例代码?
    • 好的,我明白了。那么现在我在哪里实际处理数据包?现在我可以从数据包中接收数据,但我实际上在哪里编写逻辑/代码,例如 PacketEnemy00?
    • 是的。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-05
    • 2021-04-21
    • 1970-01-01
    • 2011-01-03
    相关资源
    最近更新 更多