raknet是用cmake构建的(我这里是centos 64位环境), 从cmake很容易看出raknet的编译过程:
结构非常简单, 就是根据Source下的源文件,编译生成了一个静态/动态链接库。
目前在linux下调试了一个ServerClientTest2的例子程序, 就当前的理解看, 程序主要的结构如下:
raknet维护了好多个队列:一个发送队列(bufferedCommands), 这个队列主要是存放用户要发送的消息(比如当调用peer->send()时, 数据会先push到该队列); 还有一个发送队列(requestedConnectionQueue), 这个队列主要存放程序底层的一些消息(比如当调用peer->connect时, 内部会产生的一系列connectReuqest消息); 还有一个接收队列bufferedPacketsQueue, 接收到的消息都会暂时存放到这个队列。还有好几个对列, 后续继续完善。
线程1只负责接收对端发送过来的包, 如果没有包, 就阻塞; 如果有包, 就将包push到接收队列(bufferedPacketsQueue)。
主线程里当调用peer->send时,就会将数据放入到发送队列里头(bufferedCommands); 当调用peer->receive时,从packetReturnQueue中pop出来包。
线程2负责周期检查一些队列(包括发送队列, 接收队列), 如果接收队列有包,就将包从队列中pop出来,并进行处理; 如果发送队列有包需要发送时,就将包pop出来,并发送出去。
需要发送的数据不会消息头中添加任何信息, 所以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的数据结构。