一日一点RakNet(16)--BitStream

来源:互联网 发布:编程网站推荐 编辑:程序博客网 时间:2024/04/29 21:15
 

BitStream概述

 

       BitStream类是在RakNet命名空间下的一个辅助类,用一个封装的动态数组来打包和解包bits。它具有如下的四个优势:

       1. 动态创建数据报。

       2. 数据压缩。

       3. 写入Bits。

       4. 数据字节序转换。

       使用结构体打包数据,需要提前预定义结构体,并且将它们转化为(char *)。使用BitStream,可以在运行时根据上下文有选择地写入数据块。BitStream可以使用SerializeBitsFromIntegerRange方法和SerializeFloat16()方法压缩内置类型的数据。

       使用它写入位数据。大多数时候不需要关心这个问题。然而,当写入一个Boolean类型的数据时,bitstream仅仅自动写入一位数据。这种处理对加密也很有效,因为写入的数据不再是字节对齐的了,一次如果数据遭到窃听,截取,也无法按照正常的字节对齐查看输入内容!

 

写入数据

        Bitstream是作为模板类,可以容纳任何类型数据。如果这是一个内置的类型,例如一个NetwordIDObject,它使用部分模板实现使得类型写入更加有效。如果是局部类型(这块理解不好,应该是自己定义的一种类型),或一个结构体,bitstream写入单独的一位数据,类似于memcpy。可以传递一个包涵了多个数据成员的结构体到bitstream。但是有时你需要要单独序列化每一个元素以纠正字节序问题(例如在PCs和Macs之间的通讯需要这样来实现)。

struct MyVector
{
         float x,y,z;
} myVector;

// 没有字节序交换
bitStream.Write(myVector);

// 带有字节序交换
#undef __BITSTREAM_NATIVE_END
bitStream.Write(myVector.x);
bitStream.Write(myVector.y);
bitStream.Write(myVector.z);

// 也可以重写操作符
// Shift 操作符必须在RakNet命名空间中,或者可以使用BitStream.h中默认的命名空间。错误会在

// std::string发生
namespace RakNet
{

       RakNet::BitStream& operator << (RakNet::BitStream& out, MyVector& in)
       {
              out.WriteNormVector(in.x,in.y,in.z);
              return out;
       }


       RakNet::BitStream& operator >> (RakNet::BitStream& in, MyVector& out)
       {
             bool success = in.ReadNormVector(out.x,out.y,out.z);
              assert(success);
              return in;
       }

} // 命名空间 RakNet

// 从bitstream读取数据
myVector << bitStream;


// 向bitstream写入数据
myVector >> bitStream;

       可选—其中的一个构造函数是以长度作为参数。如果大概知道数据的大小,在构造Bitstream对象的时候可以将这个参数传递给Bitstream的构造函数,可以避免在生成bitstream对象后在动态重新分配内存。

       参考Creating pakcet了解更多的细节。

 

读取数据

       读取数据也是一样的简单。创建一个bitstream,在构造函数中赋值给它数据。

// 假设我们接收到一个数据包Packet *
BitStream myBitStream(packet->data, packet->length, false);
struct MyVector
{
       float x,y,z;
} myVector;

// 没有字节序转换
bitStream.Read(myVector);

// 要转换字节序(__BITSTREAM_NATIVE_END在RakNetDefines.h中要注释掉)
#undef __BITSTREAM_NATIVE_END
#include "BitStream.h"

bitStream.Read(myVector.x);
bitStream.Read(myVector.y);
bitStream.Read(myVector.z);

       参考Receiving Pakcet获得一个更加完整的例子。

 

序列化数据

       需要同时使用相同的函数Read和Write,可以使用BitStream::Serialize()代替Read()和Write()

 

struct MyVector
{
       float x,y,z;
       // 如果ToBitstream==true,则是写入数据, 如果ToBitstream==false,则是读取数据
       void Serialize(bool writeToBitstream, BitStream *bs)
       {
              bs->Serialize(writeToBitstream, x);
              bs->Serialize(writeToBitstream, y);
              bs->Serialize(writeToBitstream, z);
       }
} myVector;

参考Receiving Pakcet了解更多的细节

 

有用函数

参考BitStream.h查看完整的函数列表

Rese t函数

       重置bitstream,清除所有的数据。

 

Write 函数

       Write函数在bitstream的最后写入数据。应该使用类似的Read函数从bitstream中将数据读取出来。

 

Read函数

       Read函数用来读取已经存在在bitstream中的数据,从头到尾按照顺序读取。如果读到了bitstream的结尾处了,Read函数会返回false值。

 

WriteCasted,ReadCasted

       写一种类型的数据就像是它被转化为了其他类型的数据。例如WriteCasted<char>(5),等价于写入char c=5; Write(c);

 

WriteNormVector, ReadNormVector

       写入一个通常的向量,其中每一个元素的范围都是-1 — 1。每一个元素有16位。

 

WriteFloat16,ReadFloat16

       给出一个floating指针数字的最大值和最小值,除以范围65535,将结果以16个字节写入。

 

WriteNormQuat,ReadNormQuat

       在16*3 + 4位中,写入一个四元组。

 

WriteOrthMatrix,ReadOrthMatrix

       将一个正交矩阵转换为四元组,然后调用WriteNormQuat,ReadNormQuat写入和读取数据

 

GetNumberOfBitsUsed,GetNumberOfBytesUsed

       返回写入的字节数或位数。

 

GetData

       返回一个指向Bitstream内部数据的指针。这个数据是用(char *)类型使用malloc分配的,在你需要直接访问bitstream的数据时使用。

 

 

By 北洋小郭