【问题标题】:Best way to send packet with RakNet使用 RakNet 发送数据包的最佳方式
【发布时间】:2015-10-14 04:30:06
【问题描述】:

我想知道如何使用 RakNet 在客户端-服务器架构中向客户端发送数据包。在这个sample code 中,我们有这行:

peer->Send(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,packet->systemAddress,false);

然而,原型如下(来自接口类):

virtual uint32_t Send( const RakNet::BitStream * bitStream,
                       PacketPriority priority,
                       PacketReliability reliability,
                       char orderingChannel,
                       const AddressOrGUID systemIdentifier,
                       bool broadcast,
                       uint32_t forceReceiptNumber=0 )=0;

如您所见,第 5 个参数采用 AddressOrGUID,表示我们可以发送示例中的 SystemAddress,也可以发送连接机器的唯一 GUID。

有一个函数叫做:

RakNet::GetSystemAddressFromGUID();

但我不确定 RakNet 是否使用它来转换我们可以作为参数发送的 GUID(我在 RakPeer 中没有发现此方法的任何用途(RakPeerInterface 的实现),我无法找到如何每个滴答声都会发送缓冲的数据包)。

问题如下:

示例代码直接回复收到的数据包。然而,在游戏中,服务器必须发送信息而不接收来自客户端的数据包。所以我无法访问类似的东西

packet->systemAddress

因为没有收到数据包。

所以我必须在我的 Player 类中存储一些东西才能知道如何向他们发送数据包:SystemAddress 或 RakNetGUID。与 SystemAddress 相比,RakNetGUID 的存储更简单、更轻。

但是,如果 RakNet 使用 GetSystemAddressFromGUID(),则不值得,因为它有一个 O(log(n)) 算法。

我是否需要自己为每个玩家存储 SystemAddress 或 RakNet::Send() 不使用此方法和 RakNetGUID ?

谢谢!

【问题讨论】:

    标签: c++ networking packet raknet


    【解决方案1】:

    来自文档:http://www.raknet.net/raknet/manual/systemaddresses.html

    您最好通过 RakNetGUID 而不是 SystemAddress 来引用远程系统。 RakNetGUID 是 RakPeer 实例的唯一标识符,而 SystemAddress 不是。如果您打算使用 Router2 插件,则必须独占使用 RakNetGUID。

    SystemAddress 只是 IP 和端口的组合

    【讨论】:

      【解决方案2】:

      好吧,我第一次尝试理解源代码时没有正确遵循条件语句,这是一个错误,并且由于这个问题非常具体,我认为查看源代码会很棒。

      简单的答案是是的,将 RakNetGUID 存储在 Player 类中

      这里有详细信息:

      好的,首先,相关文件仅是 RakPeer.cpp。起点是:

      uint32_t RakPeer::Send( const RakNet::BitStream * bitStream,
                              PacketPriority priority,
                              PacketReliability reliability,
                              char orderingChannel,
                              const AddressOrGUID systemIdentifier,
                              bool broadcast,
                              uint32_t forceReceiptNumber ) // Line 1366
      

      然后,我们有这行调用 SendBuffered:

      SendBuffered((const char*)bitStream->GetData(),
                   bitStream->GetNumberOfBitsUsed(),
                   priority,
                   reliability,
                   orderingChannel,
                   systemIdentifier, // This is the initial AddressOrGUID
                   broadcast,
                   RemoteSystemStruct::NO_ACTION,
                   usedSendReceipt); // Line 1408
      

      在上面的方法中,我们可以知道缓冲区变量的名称:

      bufferedCommands.Push(bcs); // Line 4216
      

      并且通过搜索每个使用 bufferedCommands 的地方,我们找到了一个有意义的方法名:

      bool RakPeer::RunUpdateCycle(BitStream &updateBitStream ) // Line 5567
      

      我们可以在这里找到一个发送每个缓冲消息的循环:

      callerDataAllocationUsed=SendImmediate((char*)bcs->data,
                                             bcs->numberOfBitsToSend,
                                             bcs->priority,
                                             bcs->reliability,
                                             bcs->orderingChannel,
                                             bcs->systemIdentifier, // Initial AddressOfGUID
                                             bcs->broadcast,
                                             true,
                                             timeNS,
                                             bcs->receipt); // Line 5630
      

      RakPeer::SendImmediate() 将要求 RakPeer::GetSystemIndexFromGuid() 找到合适的索引:

      else if (systemIdentifier.rakNetGuid!=UNASSIGNED_RAKNET_GUID)
              remoteSystemIndex=GetSystemIndexFromGuid(systemIdentifier.rakNetGuid); // Line 4300
      

      最后,这最后一个方法会在找到时将索引直接存储在 RakNet::RakNetGUID 中:

      unsigned int i;
          for ( i = 0; i < maximumNumberOfPeers; i++ )
          {
              if (remoteSystemList[ i ].guid == input )
              {
                  // Set the systemIndex so future lookups will be fast
                  remoteSystemList[i].guid.systemIndex = (SystemIndex) i;
      
                  return i;
              }
          } // Line 2440
      

      如果我们使用 RakNetGUID 调用 Send(),那么它将检查是否设置了 RakNetGUID::systemIndex。如果是,则无需搜索。否则,对于第一个发送的数据包,它将有一个线性搜索时间 O(n) (n = maximumNumbersOfPeers)。

      我写这篇文章是为了帮助人们理解如果他们有同样的问题,它是如何工作的。

      【讨论】:

      • 这并没有给出完整的答案。首先如何获得 GUID?当你在服务器上得到 ID_REMOTE_NEW_INCOMING_CONNECTION 事件时,你如何获取新客户端的 GUID?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-03
      • 2011-10-10
      • 2010-11-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-27
      相关资源
      最近更新 更多