Raknet 库学习一

1. raknet结构

raknet是用cmake构建的(我这里是centos 64位环境), 从cmake很容易看出raknet的编译过程:
Raknet 库学习一_第1张图片

结构非常简单, 就是根据Source下的源文件,编译生成了一个静态/动态链接库。

2. raknet调试:

  1. 开启raknet调试: cmake -DCMAKE_BUILD_TYPE=debug 后, 即可用 gdb进行调试

3. raknet的底层模型:

目前在linux下调试了一个ServerClientTest2的例子程序, 就当前的理解看, 程序主要的结构如下:
Raknet 库学习一_第2张图片

raknet维护了好多个队列:一个发送队列(bufferedCommands), 这个队列主要是存放用户要发送的消息(比如当调用peer->send()时, 数据会先push到该队列); 还有一个发送队列(requestedConnectionQueue), 这个队列主要存放程序底层的一些消息(比如当调用peer->connect时, 内部会产生的一系列connectReuqest消息); 还有一个接收队列bufferedPacketsQueue, 接收到的消息都会暂时存放到这个队列。还有好几个对列, 后续继续完善。

线程1只负责接收对端发送过来的包, 如果没有包, 就阻塞; 如果有包, 就将包push到接收队列(bufferedPacketsQueue)。

主线程里当调用peer->send时,就会将数据放入到发送队列里头(bufferedCommands); 当调用peer->receive时,从packetReturnQueue中pop出来包。

线程2负责周期检查一些队列(包括发送队列, 接收队列), 如果接收队列有包,就将包从队列中pop出来,并进行处理; 如果发送队列有包需要发送时,就将包pop出来,并发送出去。

举例: 以client->connect的过程举例:
Raknet 库学习一_第3张图片

图 1-1

client 发送消息的过程举例:
Raknet 库学习一_第4张图片

图 1-2

需要发送的数据不会消息头中添加任何信息, 所以server端调用receive时, 收到的包的没有任何的packetIdentifier, 比如下面这个样子:

        for (p=server->Receive(); p; server->DeallocatePacket(p), p=server->Receive())
        {
            // We got a packet, get the identifier with our handy function
            // packetIdentifier 其实就是包p的第一个字节
            packetIdentifier = GetPacketIdentifier(p);

            // Check if this is a network message packet
            switch (packetIdentifier)
            {
            case ID_DISCONNECTION_NOTIFICATION:
                // Connection lost normally
                printf("ID_DISCONNECTION_NOTIFICATION from %s\n", p->systemAddress.ToString(true));;
                break;


            case ID_NEW_INCOMING_CONNECTION:
                // Somebody connected.  We have their IP now
                printf("ID_NEW_INCOMING_CONNECTION from %s with GUID %s\n", p->systemAddress.ToString(true), p->guid.ToString());
                clientID=p->systemAddress; // Record the player ID of the client

                printf("Remote internal IDs:\n");
                for (int index=0; index < MAXIMUM_NUMBER_OF_INTERNAL_IDS; index++)
                {
                    RakNet::SystemAddress internalId = server->GetInternalID(p->systemAddress, index);
                    if (internalId!=RakNet::UNASSIGNED_SYSTEM_ADDRESS)
                    {
                        printf("%i. %s\n", index+1, internalId.ToString(true));
                    }
                }

                break;

            case ID_INCOMPATIBLE_PROTOCOL_VERSION:
                printf("ID_INCOMPATIBLE_PROTOCOL_VERSION\n");
                break;

            case ID_CONNECTED_PING:
            case ID_UNCONNECTED_PING:
                printf("Ping from %s\n", p->systemAddress.ToString(true));
                break;

            case ID_CONNECTION_LOST:
                // Couldn't deliver a reliable packet - i.e. the other system was abnormally
                // terminated
                printf("ID_CONNECTION_LOST from %s\n", p->systemAddress.ToString(true));;
                break;

            // 这里是收到的数据, 这里把包的数据打印了出来
            default:
                // The server knows the static data of all clients, so we can prefix the message
                // With the name data
                printf("%s\n", p->data);

                // Relay the message.  We prefix the name for other clients.  This demonstrates
                // That messages can be changed on the server before being broadcast
                // Sending is the same as before
                sprintf(message, "%s", p->data);
                server->Send(message, (const int) strlen(message)+1, HIGH_PRIORITY, RELIABLE_ORDERED, 0, p->systemAddress, true);

                break;
            }

这一节分析了Raknet的大致框架吧, 下一节准备详细分析一下Raknet的数据结构。

你可能感兴趣的:(raknet-库)