简体   繁体   中英

Best way to send packet with RakNet

I was wondering how to send packet to client in client-server architecture with RakNet. In this sample code we have this line:

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

However, the prototype is the following (from the interface class):

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

As you can see, the 5th parameter takes a AddressOrGUID, it means we can send the SystemAddress as in the sample, but also can send the unique GUID of a connected machine.

There is a function called:

RakNet::GetSystemAddressFromGUID();

But I'm not sure if RakNet uses it to convert the GUID we can send as a parameter (I didn't find any use of this method in RakPeer (implemention of RakPeerInterface) and I'm not able to find how buffered packet are sent each tick).

The problem is the following:

The sample code replies directly to the received packet. However, in a game, server has to send information without receiving packet from client. So I don't have access to something like

packet->systemAddress

because there is no received packet.

So I will have to stock something in my Player class to know how to send them packets: SystemAddress or RakNetGUID. RakNetGUID is simpler and lighter to stock than a SystemAddress.

But, if RakNet uses GetSystemAddressFromGUID(), it's not worth because is has a O(log(n)) algorithm.

Do I need to stock the SystemAddress for each Player myself or RakNet::Send() doesn't use this method with a RakNetGUID ?

Thank you!

Ok I just did a mistake by not correctly following condition statement the first time I tried to understand the source code, and because this question is really specific, I think it would be great to look in source code.

The simple answer is Yes, store RakNetGUID in Player class

Details here:

Ok so first, file concerned is RakPeer.cpp only. The starting point is:

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

Then, we have this line where SendBuffered is called:

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

In the method above, we can know the name of the buffer variable:

bufferedCommands.Push(bcs); // Line 4216

And by searching every place where bufferedCommands is used, we find a meaningful method name:

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

We can find a loop that sends every buffered message here:

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() will ask RakPeer::GetSystemIndexFromGuid() to find the appropriate Index:

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

Finally, this last method will store the index directly in the RakNet::RakNetGUID when found:

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

If we call Send() with RakNetGUID, then it will check if RakNetGUID::systemIndex is set. If yes, it doesn't need to search. Else, it will have a linear searching time O(n) (n = maximumNumbersOfPeers) for the first packet sent.

I wrote this to help people understand how it works if they have the same question in mind.

From the doc : http://www.raknet.net/raknet/manual/systemaddresses.html

It is preferred that you refer to remote systems by RakNetGUID, instead of SystemAddress. RakNetGUID is a unique identifier for an instance of RakPeer, while SystemAddress is not. And it is necessary to exclusively use RakNetGUID if you plan to use the Router2 plugin.

SystemAddress is only the combination of the IP and the port

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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