一日一点RakNet(14)--Recieving Packets

 

接收数据包

当一个数据包到来时,例如Receive返回一个非零,处理这个数据包需要三步:

1. 确定数据包类型。使用如下的代码可以返回这个类型值。

   unsigned char GetPacketIdentifier(Packet *p)
   {
         if ((unsigned char)p->data[0] == ID_TIMESTAMP)
             return (unsigned char) p->data[sizeof(unsigned char) + sizeof(unsigned long)];
         else
             return (unsigned char) p->data[0];
   }

2. 处理数据

接收结构

       如果你原始发送一个结构体,可以按照如下的方式转化出这个结构体:

       if (GetPacketIdentifier(packet)==/* 在这里使用赋值的数据包标识符 */)

              DoMyPacketHandler(packet);

       // 可以将这个函数放到任何位置,在处理游戏的状态类中比较好

       void DoMyPacketHandler(Packet *packet)

       {

               // 将数据转化为适合类型的结构体

               MyStruct *s = (MyStruct *) packet->data;

               assert(p->length == sizeof(MyStruct)); // 如果传输的是结构体这块这样处理比较好

                if (p->length != sizeof(MyStruct))

                   return;

                // 在这里调用函数处理结构体 MyStruct *s

       }

使用注释:

       1. 将数据包的数据转换为适合类型结构体的指针,这样可以避免复制数据造成的开销。然后在这种情况下,如果你修改了结构体中的任何数据,数据包中的数据也会被修改掉。当然了,这种情况不是我们想要看到的。作为一个服务器,在中继数据的时候要多加注意,因为中继数据会引起未知的Bugs。

       2. 尽管assert不是特别必要,但是如果我们对标识符赋值错误了,assert对于发现bug非常有用。

       3.在有人要发送一个大小或类型无效的数据包,使得服务器或客户端崩溃情况时,if语句就显得非常有用。在实践中,没有发生过这样的事情,虽然没有出现过也不能说明是安全的。

 

接收一个位流数据(BitStream)

       如果你最初发送的是一个Bitstream,那就需要创建一个BitStream,按照我们的写入顺序来解析数据。使用数据和数据包的长度来创建一个BitStream。我们写入数据的时候,使用的是Write函数,那么就使用Read函数读取数据。如果前面使用的WriteCompressed函数,那读取数据就要使用ReadCompressed函数。如果我们条件性的写入任何数据,依据这个逻辑分支。在接下来的例子中给出了处理在Creating packets中的地雷的数据:

       void DoMyPacketHandler(Packet *packet)

       {

                Bitstream myBitStream(packet->data, packet->length, false); // false指定不拷贝数据,提高效率

               myBitStream.Read(useTimeStamp);

               myBitStream.Read(timeStamp);

               myBitStream.Read(typeId);

               bool isAtZero;

               myBitStream.Read(isAtZero);

               if (isAtZero==false)

               {

                          x=0.0f;

                         y=0.0f;

                         z=0.0f;

                }

               else

               {

                          myBitStream.Read(x);

                         myBitStream.Read(y);

                          myBitStream.Read(z);

                }

        

                myBitStream.Read(networkID); // 在结构体中这里是 NetworkID networkId

               myBitStream.Read(systemAddress); // 在结构体中这里是SystemAddress systemAddress

       }

3. 通过将数据包传递给RakPeerInterface实例的DeallocatePakcet(Packet *packet)释放数据包。

 

By 北洋小郭

你可能感兴趣的:(游戏,服务器,bugs)