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 北洋小郭