使用Beetle进行高效的自定义二进制序列化
Beetle提供了BufferWriter和BufferReader两个对象分别把数据写入二进制流和从二进制流中读取数据,由于大部分操作是基于unsafe的实现所以其数据的写入和读取效率非常高效。由于数据类型在写入的MemoryStream的时候需要做一个byte[]的转换,而Beetle所提供的BufferWriter和BufferReader很多数据读取和写入都是指针值复制,所以在整体效率会比平常用MemoryStream写入读取数据成员相对高效。同样基于指针值复制的好处在于组件在序列化数据类型的时候不会有额外的byte[]产生,即使序列化的对象的大小和序列化的数量都会有着良好的内存使用效率,在高密集的对象序列化时候可以让GC的工作压力减到最低。既然是手动序列化那其缺点就是需要手写代码来描述序列化过程,但也正因为这样用户可以根据自己实际的需要把对象序列化成网络传输的二进制协议流。
Beetle通过一个接口来制定对象的序列化过程,对象只需要实现一个IMessage即可。
public class Order : IMessage { public int OrderID; public string CustomerID; public int EmployeeID; public long OrderDate; public long RequiredDate; public string ShipName; public string ShipAddress; public string ShipCity; public string ShipRegion; public string ShipPostalCode; public string ShipCountry; public void Save(BufferWriter writer) { writer.Write(OrderID); writer.Write(CustomerID); writer.Write(EmployeeID); writer.Write(OrderDate); writer.Write(RequiredDate); writer.Write(ShipName); writer.Write(ShipAddress); writer.Write(ShipCity); writer.Write(ShipRegion); writer.Write(ShipPostalCode); writer.Write(ShipCountry); } public void Load(BufferReader reader) { OrderID = reader.ReadInt32(); CustomerID = reader.ReadString(); EmployeeID = reader.ReadInt32(); OrderDate = reader.ReadInt64(); RequiredDate = reader.ReadInt64(); ShipName = reader.ReadString(); ShipAddress = reader.ReadString(); ShipCity = reader.ReadString(); ShipRegion = reader.ReadString(); ShipPostalCode = reader.ReadString(); ShipCountry = reader.ReadString(); } }
接口主要有两个方法,一个是描述信息如果写入流中Save方法,而另一个则是描述从流中获取数据Load方法。用于的两个对象分别是BufferWriter和BufferReader,这两个对象提供很多基础类型数据写入功能。
BufferWriter
public void Write(bool value); public void Write(bool[] value); public void Write(byte value); public void Write(byte[] value); public void Write(ByteArraySegment bas); public void Write(char value); public void Write(char[] value); public void Write(DateTime datetime); public void Write(DateTime[] value); public void Write(double value); public void Write(double[] value); public void Write(float value); public void Write(float[] value); public void Write(IList<bool> values); public void Write(IList<char> values); public void Write(IList<DateTime> values); public void Write(IList<double> values); public void Write(IList<float> values); public void Write(IList<int> values); public void Write(IList<long> values); public void Write(IList<short> values); public void Write(IList<string> values); public void Write<T>(IList<T> objs) where T : IMessage; public void Write(IMessage obj); public void Write(int value); public void Write(int[] value); public void Write(long value); public void Write(long[] value); public void Write(short value); public void Write(short[] value); public void Write(string value); public void Write(string[] value); public void Write(uint value); public void Write(ulong value); public void Write(ushort value); public void Write(byte[] value, int start, int length); public IList<ByteArraySegment> WriteHeadSize(); public IList<ByteArraySegment> WriteReturnSegment(byte[] value, int start, int length); public void WriteShortString(string value); public void WriteString(string value); public void WriteVariant(double value); public void WriteVariant(float value); public void WriteVariant(int value); public void WriteVariant(long value); public void WriteVariant(uint value); public void WriteVariant(ulong value);
BufferReader
public ByteArraySegment Read(int count); public void Read(int count, ByteArraySegment bas); public int Read32Variant(); public long Read64Variant(); public bool ReadBool(); public IList<bool> ReadBoolList(); public bool[] ReadBools(); public byte ReadByte(); public byte[] ReadByteArray(); public void ReadByteArray(ByteArraySegment bas); public byte[] ReadBytes(int count); public char ReadChar(); public IList<char> ReadCharList(); public char[] ReadChars(); public DateTime ReadDate(); public DateTime[] ReadDates(); public IList<DateTime> ReadDateTimeList(); public double ReadDouble(); public IList<double> ReadDoubleList(); public double[] ReadDoubles(); public double ReadDoubleVariant(); public float ReadFloat(); public IList<float> ReadFloatList(); public float[] ReadFloats(); public float ReadFloatVariant(); public short ReadInt16(); public IList<short> ReadInt16List(); public short[] ReadInt16s(); public int ReadInt32(); public IList<int> ReadInt32List(); public int[] ReadInt32s(); public long ReadInt64(); public IList<long> ReadInt64List(); public long[] ReadInt64s(); public T ReadObject<T>() where T : IMessage, new(); public T ReadObject<T>(MessagePool<T> pool) where T : IMessage, IObjectReset, new(); public IList<T> ReadObjects<T>() where T : IMessage, new(); public IList<T> ReadObjects<T>(MessagePool<T> pool) where T : IMessage, IObjectReset, new(); public string ReadShortString(); public string ReadString(); public string ReadString(int count); public IList<string> ReadStringList(); public string[] ReadStrings(); public uint ReadU32Variant(); public ulong ReadU64Variant(); public ushort ReadUInt16(); public uint ReadUInt32(); public ulong ReadUInt64(); public byte[] ToBytes();
组件提供了ObjectFormatter对象把数据写入到一个内存块中
Beetle.ByteArraySegment segment = new Beetle.ByteArraySegment(1024, false); BeetleOrder order = new BeetleOrder(); order.OrderID = 10248; order.CustomerID = "WILMK"; order.EmployeeID = 5; order.OrderDate = 629720352000000000; order.RequiredDate = 629744544000000000; order.ShipAddress = "59 rue de l'Abbaye"; order.ShipCity = "Reims"; order.ShipCountry = "France"; order.ShipName = "Vins et alcools Chevalier"; order.ShipPostalCode = "51100"; order.ShipRegion = "RJ"; Beetle.ObjectFormatter.Serialize(order, segment);
组件并没有直接返回byte[]的方式,其实主要目的是不让组件内部产生新的byte[],通过用户提供一个数据块来把对象信息填充。反序列化对象也是很简单的工作
order= Beetle.ObjectFormatter.Deserialize<BeetleOrder>(segment);
ByteArraySegment除了描述一个内存块外,它还提供了简单的DES加密方法;通过它可以简单地对序列化的信息进行DES加密和解密。
DESCryptoServiceProvider des = new DESCryptoServiceProvider(); ByteArraySegment segment = new ByteArraySegment(1024, false); ByteArraySegment esegment = new ByteArraySegment(1024, false); ObjectFormatter.Serialize(order, segment); segment.EncryptTo(esegment, des); esegment.DecryptTo(segment, des); order= new Order(); ObjectFormatter.Deserialize(order, segment);
性能测试情况