繁体   English   中英

使用RakNet发送数据包的最佳方法

[英]Best way to send packet with RakNet

我想知道如何使用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))算法。

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

谢谢!

好的,我第一次尝试理解源代码时没有正确遵循条件语句就犯了一个错误,并且由于这个问题确实很具体,所以我认为最好查看源代码。

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

我写这篇文章的目的是帮助人们了解相同的问题时的工作原理。

从文档中: http : //www.raknet.net/raknet/manual/systemaddresses.html

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

SystemAddress只是IP和端口的组合

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM