1

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

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)) 算法。

我是否需要自己为每个 Player 存储 SystemAddress 或 RakNet::Send() 不将此方法与 RakNetGUID 一起使用?

谢谢!

4

2 回答 2

0

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

简单的答案是肯定的,将 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)。

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

于 2015-07-23T19:46:56.960 回答
0

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

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

SystemAddress 只是 IP 和端口的组合

于 2019-02-02T22:51:52.157 回答