#define UNIT_TEST
using System;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
namespace Hazel
{
///
///
///
public class MessageReader : IRecyclable
{
public static readonly ObjectPool ReaderPool = new ObjectPool(() => new MessageReader());
public byte[] Buffer; // √ 缓冲区,会被子协议共享这个缓冲区
public byte Tag; // √ 协议名
public int Length; // √ 协议长度,对应的是MessageWriter里写入的2bytes包长度(不含length和tag)
public int Offset; // √ length和tag后面的位置(在Buffer中的位置),不是游标,不会随读取发生改变。会影响readHead的值
//数据位于Buffer中Offset索引开始Length长度,协议位于Buffer中Offset-3开始的Length+3长度
public int BytesRemaining => this.Length - this.Position;
private MessageReader Parent; // 保存父协议索引,和父协议共享父协议的Buffer
public int Position
{
get { return this._position; }
set
{
this._position = value; // value是
this.readHead = value + Offset;
}
}
private int _position; // √ 读取游标,相对于协议内容部分的偏移,从0开始,子协议也是从0开始,不是在Buffer中的索引
private int readHead; // √ 读取游标,协议头部在Buffer中的位置,参考ReadMessage()
public static MessageReader GetSized(int minSize)
{
var output = ReaderPool.GetObject();
if (output.Buffer == null || output.Buffer.Length < minSize)
{
output.Buffer = new byte[minSize];
}
else
{
Array.Clear(output.Buffer, 0, output.Buffer.Length);
}
output.Offset = 0;
output.Position = 0;
output.Tag = byte.MaxValue;
return output;
}
public static MessageReader Get(byte[] buffer)
{
var output = ReaderPool.GetObject();
output.Buffer = buffer;
output.Offset = 0;
output.Position = 0;
output.Length = buffer.Length;
output.Tag = byte.MaxValue;
return output;
}
///
/// 创建一个新的message,保存source。用于缓存message,因为source所在的原父message可能会被销毁,如果需要延迟处理消息,需要拷贝一份新的
///
///
///
public static MessageReader CopyMessageIntoParent(MessageReader source)
{
var output = MessageReader.GetSized(source.Length + 3); //3=2bytes(length) + 1byte(tag)
System.Buffer.BlockCopy(source.Buffer, source.Offset - 3, output.Buffer, 0, source.Length + 3);
output.Offset = 0;
output.Position = 0;
output.Length = source.Length + 3;
return output;
}
// 没用
public static MessageReader Get(MessageReader source)
{
var output = MessageReader.GetSized(source.Buffer.Length);
System.Buffer.BlockCopy(source.Buffer, 0, output.Buffer, 0, source.Buffer.Length);
output.Offset = source.Offset;
output._position = source._position;
output.readHead = source.readHead;
output.Length = source.Length;
output.Tag = source.Tag;
return output;
}
public static MessageReader Get(byte[] buffer, int offset)
{
// Ensure there is at least a header
if (offset + 3 > buffer.Length) return null; //3=length+tag
var output = ReaderPool.GetObject();
output.Buffer = buffer;
output.Offset = offset;
output.Position = 0;
output.Length = output.ReadUInt16(); // 读到的值为length
output.Tag = output.ReadByte();
output.Offset += 3;
output.Position = 0;
return output;
}
///
/// Produces a MessageReader using the parent's buffer. This MessageReader should **NOT** be recycled.
///
public MessageReader ReadMessage()
{
// Ensure there is at least a header
if (this.BytesRemaining < 3) throw new InvalidDataException($"ReadMessage header is longer than message length: 3 of {this.BytesRemaining}");
MessageReader output = new MessageReader();
output.Parent = this;
output.Buffer = this.Buffer;
output.Offset = this.readHead; // 下面会读取
output.Position = 0;
// 读length和tag的值并保存在字段里
output.Length = output.ReadUInt16();
output.Tag = output.ReadByte();
// Offset, readHead齐步走,移到Length和Tag后面,_position=0
output.Offset += 3; // 3=length+tag
output.Position = 0;
if (this.BytesRemaining < output.Length + 3) throw new InvalidDataException($"Message Length at Position {this.readHead} is longer than message length: {output.Length + 3} of {this.BytesRemaining}");
this.Position += output.Length + 3; //跳过整个子协议
return output;
}
///
/// Produces a MessageReader with a new buffer. This MessageReader should be recycled.
///
public MessageReader ReadMessageAsNewBuffer()
{
if (this.BytesRemaining < 3) throw new InvalidDataException($"ReadMessage header is longer than message length: 3 of {this.BytesRemaining}");
var len = this.ReadUInt16();
var tag = this.ReadByte();
if (this.BytesRemaining < len) throw new InvalidDataException($"Message Length at Position {this.readHead} is longer than message length: {len} of {this.BytesRemaining}");
var output = MessageReader.GetSized(len);
Array.Copy(this.Buffer, this.readHead, output.Buffer, 0, len);
output.Length = len;
output.Tag = tag;
this.Position += output.Length;
return output;
}
// 没用,注释掉了
//public MessageWriter StartWriter()
//{
// var output = new MessageWriter(this.Buffer);
// output.Position = this.readHead;
// return output;
//}
public MessageReader Duplicate()
{
var output = GetSized(this.Length);
Array.Copy(this.Buffer, this.Offset, output.Buffer, 0, this.Length);
output.Length = this.Length;
output.Offset = 0;
output.Position = 0;
return output;
}
public void RemoveMessage(MessageReader reader)
{
var temp = MessageReader.GetSized(reader.Buffer.Length);
try
{
var headerOffset = reader.Offset - 3;
var endOfMessage = reader.Offset + reader.Length;
var len = reader.Buffer.Length - endOfMessage;
Array.Copy(reader.Buffer, endOfMessage, temp.Buffer, 0, len);
Array.Copy(temp.Buffer, 0, this.Buffer, headerOffset, len);
this.AdjustLength(reader.Offset, reader.Length + 3);
}
finally
{
temp.Recycle();
}
}
#if UNIT_TEST // 我自己加的,作为备注
///
/// 仅用于单元测试的方法
///
/// 父reader
///
public void InsertMessage(MessageReader reader, MessageWriter writer)
{
var temp = MessageReader.GetSized(reader.Buffer.Length);
try
{
var headerOffset = reader.Offset - 3; // headerOffset是length+tag,这个方法仅仅接受reader不含sendoption的情况
var startOfMessage = reader.Offset; // 头部后面的数据开始的索引
var len = reader.Buffer.Length - startOfMessage; // 疑似写错了,应该是headerOffset
int writerOffset = 3;// √ 跳过header
switch (writer.SendOption)
{
case SendOption.Reliable:
writerOffset = 3;
break;
case SendOption.None:
writerOffset = 1;
break;
}
//store the original buffer in temp
Array.Copy(reader.Buffer, headerOffset, temp.Buffer, 0, len);
//put the contents of writer in at headerOffset
Array.Copy(writer.Buffer, writerOffset, this.Buffer, headerOffset, writer.Length-writerOffset);
//put the original buffer in after that
Array.Copy(temp.Buffer, 0, this.Buffer, headerOffset + (writer.Length-writerOffset), len - writer.Length);
this.AdjustLength(-1 * reader.Offset , -1 * (writer.Length - writerOffset));
}
finally
{
temp.Recycle();
}
}
#endif
private void AdjustLength(int offset, int amount)
{
if (this.readHead > offset)
{
this.Position -= amount;
}
if (Parent != null)
{
var lengthOffset = this.Offset - 3;
var curLen = this.Buffer[lengthOffset]
| (this.Buffer[lengthOffset + 1] << 8);
curLen -= amount;
this.Length -= amount;
this.Buffer[lengthOffset] = (byte)curLen;
this.Buffer[lengthOffset + 1] = (byte)(this.Buffer[lengthOffset + 1] >> 8);
Parent.AdjustLength(offset, amount);
}
}
public void Recycle()
{
this.Parent = null;
ReaderPool.PutObject(this);
}
#region Read Methods
public bool ReadBoolean()
{
byte val = this.FastByte();
return val != 0;
}
public sbyte ReadSByte()
{
return (sbyte)this.FastByte();
}
public byte ReadByte()
{
return this.FastByte();
}
public ushort ReadUInt16()
{
ushort output =
(ushort)(this.FastByte()
| this.FastByte() << 8);
return output;
}
public short ReadInt16()
{
short output =
(short)(this.FastByte()
| this.FastByte() << 8);
return output;
}
public uint ReadUInt32()
{
uint output = this.FastByte()
| (uint)this.FastByte() << 8
| (uint)this.FastByte() << 16
| (uint)this.FastByte() << 24;
return output;
}
public int ReadInt32()
{
int output = this.FastByte()
| this.FastByte() << 8
| this.FastByte() << 16
| this.FastByte() << 24;
return output;
}
public ulong ReadUInt64()
{
ulong output = (ulong)this.FastByte()
| (ulong)this.FastByte() << 8
| (ulong)this.FastByte() << 16
| (ulong)this.FastByte() << 24
| (ulong)this.FastByte() << 32
| (ulong)this.FastByte() << 40
| (ulong)this.FastByte() << 48
| (ulong)this.FastByte() << 56;
return output;
}
public long ReadInt64()
{
long output = (long)this.FastByte()
| (long)this.FastByte() << 8
| (long)this.FastByte() << 16
| (long)this.FastByte() << 24
| (long)this.FastByte() << 32
| (long)this.FastByte() << 40
| (long)this.FastByte() << 48
| (long)this.FastByte() << 56;
return output;
}
public unsafe float ReadSingle()
{
float output = 0;
fixed (byte* bufPtr = &this.Buffer[this.readHead])
{
byte* outPtr = (byte*)&output;
*outPtr = *bufPtr;
*(outPtr + 1) = *(bufPtr + 1);
*(outPtr + 2) = *(bufPtr + 2);
*(outPtr + 3) = *(bufPtr + 3);
}
this.Position += 4;
return output;
}
public string ReadString()
{
int len = this.ReadPackedInt32();
if (this.BytesRemaining < len) throw new InvalidDataException($"Read length is longer than message length: {len} of {this.BytesRemaining}");
string output = UTF8Encoding.UTF8.GetString(this.Buffer, this.readHead, len);
this.Position += len;
return output;
}
public byte[] ReadBytesAndSize()
{
int len = this.ReadPackedInt32();
if (this.BytesRemaining < len) throw new InvalidDataException($"Read length is longer than message length: {len} of {this.BytesRemaining}");
return this.ReadBytes(len);
}
public byte[] ReadBytes(int length)
{
if (this.BytesRemaining < length) throw new InvalidDataException($"Read length is longer than message length: {length} of {this.BytesRemaining}");
byte[] output = new byte[length];
Array.Copy(this.Buffer, this.readHead, output, 0, output.Length);
this.Position += output.Length;
return output;
}
///
public int ReadPackedInt32()
{
return (int)this.ReadPackedUInt32();
}
///
public uint ReadPackedUInt32()
{
bool readMore = true;
int shift = 0;
uint output = 0;
while (readMore)
{
if (this.BytesRemaining < 1) throw new InvalidDataException($"Read length is longer than message length.");
byte b = this.ReadByte();
if (b >= 0x80)
{
readMore = true;
b ^= 0x80;
}
else
{
readMore = false;
}
output |= (uint)(b << shift);
shift += 7;
}
return output;
}
#endregion
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private byte FastByte()
{
this._position++;
return this.Buffer[this.readHead++];
}
public unsafe static bool IsLittleEndian()
{
byte b;
unsafe
{
int i = 1;
byte* bp = (byte*)&i;
b = *bp;
}
return b == 1;
}
}
}