From 949f5accd281a051e5e2eeb3df8767b4794b6a1e Mon Sep 17 00:00:00 2001 From: chai <215380520@qq.com> Date: Sat, 14 Oct 2023 12:06:40 +0800 Subject: + Message --- Projects/Message/Message/Message.csproj | 13 +- Projects/Message/Message/MessageReader.cs | 252 ++++++++++++-------- Projects/Message/Message/MessageWriter.cs | 80 ++++--- Projects/Message/Message/MessageWriterTests.cs | 260 +++++++++++++++++++++ .../Message/Properties/Settings.Designer.cs | 26 +++ .../Message/Message/Properties/Settings.settings | 6 + Projects/Message/Message/UnitTest1.cs | 16 -- Tools/Hazel-Networking/Hazel/MessageReader.cs | 19 +- Tools/Hazel-Networking/Hazel/MessageWriter.cs | 24 +- 9 files changed, 523 insertions(+), 173 deletions(-) create mode 100644 Projects/Message/Message/MessageWriterTests.cs create mode 100644 Projects/Message/Message/Properties/Settings.Designer.cs create mode 100644 Projects/Message/Message/Properties/Settings.settings delete mode 100644 Projects/Message/Message/UnitTest1.cs diff --git a/Projects/Message/Message/Message.csproj b/Projects/Message/Message/Message.csproj index f2f13d5..a15b051 100644 --- a/Projects/Message/Message/Message.csproj +++ b/Projects/Message/Message/Message.csproj @@ -26,7 +26,7 @@ full false bin\Debug\ - DEBUG;TRACE + TRACE;DEBUG;UNIT_TEST prompt 4 true @@ -54,12 +54,21 @@ + - + + True + True + Settings.settings + + + SettingsSingleFileGenerator + Settings.Designer.cs + diff --git a/Projects/Message/Message/MessageReader.cs b/Projects/Message/Message/MessageReader.cs index 7ec134b..b49f9e2 100644 --- a/Projects/Message/Message/MessageReader.cs +++ b/Projects/Message/Message/MessageReader.cs @@ -7,38 +7,63 @@ using System.Text; namespace MultiplayerToolkit { /// - /// + /// å�¯ä»¥å¤„ç�†åµŒå¥—消æ�¯çš„结构,和MessageWriteré…�对 /// public class MessageReader : IRecyclable { public static readonly ObjectPool ReaderPool = new ObjectPool(() => new MessageReader()); - public byte[] Buffer; // √ 缓冲区,会被å­�å��议共享这个缓冲区 - public byte Tag; // √ å��è®®å�� + public byte[] Buffer; // 缓冲区,会被å­�消æ�¯å…±äº«è¿™ä¸ªç¼“冲区 - public int Length; // √ å��议长度,对应的是MessageWriter里写入的2bytes包长度(ä¸�å�«lengthå’Œtag) - public int Offset; // √ lengthå’Œtagå�Žé�¢çš„ä½�置(在Buffer中的ä½�置),ä¸�是游标,ä¸�会éš�读å�–å�‘生改å�˜ã€‚会影å“�readHead的值 + // 消æ�¯é•¿åº¦ï¼Œå®šå€¼ + // * 如果是é�žæ ¹æ¶ˆæ�¯ï¼Œå¯¹åº”的是MessageWriter里写入的2bytes包长度,å�³ä¸�å�«length的长度 + // * 如果是根消æ�¯ï¼ŒLength是整个有效数æ�®åœ¨Buffer中的长度,包括Length + public int Length; - //æ•°æ�®ä½�于Buffer中Offset索引开始Length长度,å��è®®ä½�于Buffer中Offset-3开始的Length+3长度 + // 有效数æ�®å��移,定值,游标会在这个基础上å��ç§» + // * 如果是é�žæ ¹æ¶ˆæ�¯ï¼ŒOffset在Lengthå�Žé�¢çš„ä½�ç½® + // * 如果是根消æ�¯ï¼ŒOffset等于0,表示有效数æ�®åœ¨Buffer中的å��ç§» + public int Offset; public int BytesRemaining => this.Length - this.Position; - private MessageReader Parent; // ä¿�存父å��议索引,和父å��议共享父å��议的Buffer + public int TotalLength => this.Length + this.Offset; + + private MessageReader Parent; // ä¿�存父消æ�¯ç´¢å¼•,和父消æ�¯å…±äº«çˆ¶æ¶ˆæ�¯çš„Buffer + + // 是å�¦æ˜¯æ ¹æ¶ˆæ�¯ï¼Œæ ¹æ¶ˆæ�¯ä¸‹é�¢åŒ…å�«å¤šä¸ªå­�消æ�¯ï¼Œå­�消æ�¯å�¯ä»¥åµŒå¥—é‡�孙消æ�¯ + public bool IsRoot + { + get { return Parent == null; } + } + + // å­�消æ�¯å�¯è¯» + public bool IsReadable + { + get { return this.Parent != null; } + } public int Position { get { return this._position; } set { - this._position = value; // value是 + this._position = value; this.readHead = value + Offset; } } - private int _position; // √ 读å�–游标,相对于å��议内容部分的å��移,从0开始,å­�å��议也是从0开始,ä¸�是在Buffer中的索引 - private int readHead; // √ 读å�–游标,å��议头部在Buffer中的ä½�置,å�‚考ReadMessage() + private int _position; // 读å�–游标,相对于消æ�¯å†…容部分的å��移,从0开始,å­�消æ�¯ä¹Ÿæ˜¯ä»Ž0开始,ä¸�是在Buffer中的索引 + private int readHead; // 读å�–游标,消æ�¯å¤´éƒ¨åœ¨Buffer中的ä½�置,å�‚考ReadMessage() - public static MessageReader GetSized(int minSize) +#region 创建 + /// + /// 创建一个容é‡�至少为minSize的空缓冲区 + /// + /// + /// + /// + public static MessageReader GetSized(int minSize, bool exactly = false) { var output = ReaderPool.GetObject(); @@ -48,15 +73,25 @@ namespace MultiplayerToolkit } else { + if(exactly && output.Buffer.Length > minSize) + { + output.Buffer = new byte[minSize]; + } Array.Clear(output.Buffer, 0, output.Buffer.Length); } output.Offset = 0; + output.Length = 0; output.Position = 0; - output.Tag = byte.MaxValue; + output.Parent = null; return output; } + /// + /// 将缓冲区å°�装为根MessageReader,ä¸�æ‹·è´� + /// + /// + /// public static MessageReader Get(byte[] buffer) { var output = ReaderPool.GetObject(); @@ -65,53 +100,60 @@ namespace MultiplayerToolkit output.Offset = 0; output.Position = 0; output.Length = buffer.Length; - output.Tag = byte.MaxValue; + output.Parent = null; return output; } /// - /// 创建一个新的父message,ä¿�å­˜source。用于缓存message,因为source所在的原父messageå�¯èƒ½ä¼šè¢«é”€æ¯�,如果需è¦�延迟处ç�†æ¶ˆæ�¯ï¼Œéœ€è¦�æ‹·è´�一份新的 + /// æ‹·è´�buffer,å°�装为根MessageReader /// - /// + /// /// - public static MessageReader CopyMessageIntoParent(MessageReader source) + public static MessageReader GetAndCopy(byte[] buffer) { - 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); + var output = ReaderPool.GetObject(); + byte[] _buffer = new byte[buffer.Length]; + Array.Copy(buffer, _buffer, buffer.Length); + output.Buffer = _buffer; output.Offset = 0; output.Position = 0; - output.Length = source.Length + 3; + output.Length = _buffer.Length; + output.Parent = null; return output; } /// - /// 完全å¤�制 一份 + /// 创建一个新的父message,ä¿�å­˜source。用于缓存message,因为source所在的原父messageå�¯èƒ½ä¼šè¢«é”€æ¯�,如果需è¦�延迟处ç�†æ¶ˆæ�¯ï¼Œéœ€è¦�æ‹·è´�一份新的 /// /// /// - public static MessageReader Get(MessageReader source) + public static MessageReader CopyMessageIntoParent(MessageReader source) { - var output = MessageReader.GetSized(source.Buffer.Length); - System.Buffer.BlockCopy(source.Buffer, 0, output.Buffer, 0, source.Buffer.Length); + var output = MessageReader.GetSized(source.Length + 2); //2=2bytes(length) + System.Buffer.BlockCopy(source.Buffer, source.Offset - 2, output.Buffer, 0, source.Length + 2); - output.Offset = source.Offset; - - output._position = source._position; - output.readHead = source.readHead; - - output.Length = source.Length; - output.Tag = source.Tag; + output.Offset = 0; + output.Position = 0; + output.Length = source.Length + 2; + output.Parent = null; return output; } - public static MessageReader Get(byte[] buffer, int offset) +#if UNIT_TEST + /// + /// 用于测试,引用buffer的一部分作为child message,å�Žç»­å�¯ä»¥ç›´æŽ¥è¯»å�– + /// + /// + /// + /// + public static MessageReader GetChildMessage(byte[] buffer, int offset) { - // Ensure there is at least a header - if (offset + 3 > buffer.Length) return null; + // ç¡®ä¿�至少有一个length + if (offset + 2 > buffer.Length) return null; var output = ReaderPool.GetObject(); @@ -120,52 +162,54 @@ namespace MultiplayerToolkit output.Position = 0; output.Length = output.ReadUInt16(); // 读到的值为length - output.Tag = output.ReadByte(); - output.Offset += 3; + output.Offset += 2; output.Position = 0; + output.Parent = null; return output; } +#endif + +#endregion /// - /// 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}"); + // 至少有一个length + if (this.BytesRemaining < 2) 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.Offset = this.readHead; output.Position = 0; - // 读lengthå’Œtag的值并ä¿�存在字段里 - output.Length = output.ReadUInt16(); - output.Tag = output.ReadByte(); + output.Length = output.ReadUInt16(); // length - // Offset, readHeadé½�步走,移到Lengthå’ŒTagå�Žé�¢ï¼Œ_position=0 - output.Offset += 3; // 3=length+tag + output.Offset += 2; // 2=length 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}"); + // æ•°æ�®ä¸�å…¨ + if (this.BytesRemaining < output.Length + 2) throw new InvalidDataException($"Message Length at Position {this.readHead} is longer than message length: {output.Length + 2} of {this.BytesRemaining}"); - this.Position += output.Length + 3; //跳过整个å­�å��è®® + this.Position += output.Length + 2; //跳过整个å­�消æ�¯ return output; } +#if UNIT_TEST /// - /// Produces a MessageReader with a new buffer. This MessageReader should be recycled. + /// 仅用于测试,返回一个å�¯è¯»å­�消æ�¯ï¼Œå¹¶ä¸”æ‹·è´�æ•°æ�®ï¼Œå�¯å›žæ”¶ + /// Offset为0,开头没有Lengthæ•°æ�® /// public MessageReader ReadMessageAsNewBuffer() { - if (this.BytesRemaining < 3) throw new InvalidDataException($"ReadMessage header is longer than message length: 3 of {this.BytesRemaining}"); + if (this.BytesRemaining < 2) throw new InvalidDataException($"ReadMessage header is longer than message length: 3 of {this.BytesRemaining}"); - var len = this.ReadUInt16(); - var tag = this.ReadByte(); + var len = this.ReadUInt16(); // Position += 2 if (this.BytesRemaining < len) throw new InvalidDataException($"Message Length at Position {this.readHead} is longer than message length: {len} of {this.BytesRemaining}"); @@ -174,19 +218,14 @@ namespace MultiplayerToolkit Array.Copy(this.Buffer, this.readHead, output.Buffer, 0, len); output.Length = len; - output.Tag = tag; + //output.Tag = tag; this.Position += output.Length; return output; } +#endif - public MessageWriter StartWriter() - { - var output = new MessageWriter(this.Buffer); - output.Position = this.readHead; - return output; - } - +#if UNIT_TEST public MessageReader Duplicate() { var output = GetSized(this.Length); @@ -200,60 +239,65 @@ namespace MultiplayerToolkit public void RemoveMessage(MessageReader reader) { - var temp = MessageReader.GetSized(reader.Buffer.Length); + MessageReader temp = null; try { - var headerOffset = reader.Offset - 3; - var endOfMessage = reader.Offset + reader.Length; - var len = reader.Buffer.Length - endOfMessage; + var headerOffset = reader.Offset - 2; + var endOfMessage = reader.Offset + reader.Length; // 有效部分的å�Žä¸€ä¸ªbyte + var len = this.TotalLength - endOfMessage; + temp = MessageReader.GetSized(len); 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); + this.AdjustLength(reader.Offset, reader.Length + 2); } finally { - temp.Recycle(); + if(temp != null) + { + temp.Recycle(); + } } } - //public void InsertMessage(MessageReader reader, MessageWriter writer) - //{ - // var temp = MessageReader.GetSized(reader.Buffer.Length); - // try - // { - // var headerOffset = reader.Offset - 3; - // var startOfMessage = reader.Offset; - // var len = reader.Buffer.Length - startOfMessage; - // int writerOffset = 3; - // 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(); - // } - //} + /// + /// 在readerå‰�é�¢æ�’入一æ�¡æ¶ˆæ�¯ + /// + /// 父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 - headerOffset; // 疑似写错了,应该是headerOffset + int writerOffset = 0; + + //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(); + } + } + /// + /// 递归调整length值 + /// + /// å­�消æ�¯çš„Offset值 + /// å­�消æ�¯æ€»é•¿åº¦ï¼Œå�«length private void AdjustLength(int offset, int amount) { if (this.readHead > offset) @@ -263,7 +307,7 @@ namespace MultiplayerToolkit if (Parent != null) { - var lengthOffset = this.Offset - 3; + var lengthOffset = this.Offset - 2; var curLen = this.Buffer[lengthOffset] | (this.Buffer[lengthOffset + 1] << 8); @@ -271,19 +315,21 @@ namespace MultiplayerToolkit this.Length -= amount; this.Buffer[lengthOffset] = (byte)curLen; - this.Buffer[lengthOffset + 1] = (byte)(this.Buffer[lengthOffset + 1] >> 8); + this.Buffer[lengthOffset + 1] = (byte)(curLen >> 8); Parent.AdjustLength(offset, amount); } } +#endif + public void Recycle() { this.Parent = null; ReaderPool.PutObject(this); } - #region Read Methods +#region Read Methods public bool ReadBoolean() { byte val = this.FastByte(); @@ -444,7 +490,7 @@ namespace MultiplayerToolkit return output; } - #endregion +#endregion [MethodImpl(MethodImplOptions.AggressiveInlining)] private byte FastByte() diff --git a/Projects/Message/Message/MessageWriter.cs b/Projects/Message/Message/MessageWriter.cs index 7646135..845a901 100644 --- a/Projects/Message/Message/MessageWriter.cs +++ b/Projects/Message/Message/MessageWriter.cs @@ -10,48 +10,42 @@ namespace MultiplayerToolkit /// ´ÓAmongUsÄùýÀ´£¬È¥µôÁ˰üÍ·Ïà¹Ø´úÂë /// ½á¹¹ /// ------------------------------------- - /// 2bytes (ushort)ЭÒéµÄ³¤¶È£¬²»°üÀ¨Õâ2bytes - /// ------------------------------------- - /// 1byte ЭÒéÀàÐÍ£¬ÄÚÖÃЭÒé0¡¢Íæ¼Ò×Ô¶¨ÒåЭÒé1 - /// (2byte) (Èç¹ûÊÇÍæ¼Ò×Ô¶¨ÒåЭÒ飬Ìṩһ¸ömodÐòºÅ£¬Steam.UGC.ItemµÄidÊÇulong 8bytesÓеã´ó£¬»»³ÉÐòºÅ£¬×î¶àÖ§³Ö65535¸ömod) - /// 2byte (ushort)ЭÒéID 0-65535 + /// 2bytes (ushort)ÏûÏ¢µÄ³¤¶È£¬²»°üÀ¨Õâ2bytes + /// (------------------------------------- + /// 1byte ÏûÏ¢ÀàÐÍ£¬ÄÚÖÃÏûÏ¢0¡¢Íæ¼Ò×Ô¶¨ÒåÏûÏ¢1 + /// (2byte) (Èç¹ûÊÇÍæ¼Ò×Ô¶¨ÒåÏûÏ¢£¬Ìṩһ¸ömodÐòºÅ£¬Steam.UGC.ItemµÄidÊÇulong 8bytesÓеã´ó£¬»»³ÉÐòºÅ£¬×î¶àÖ§³Ö65535¸ömod) + /// 2byte (ushort)ÏûÏ¢ID 0-65535 /// ÄÚÈÝ - /// ------------------------------------- + /// -------------------------------------) /// public class MessageWriter : IRecyclable { public const int BYTE_COUNT_OF_LENGTH = 2; // ³¤¶ÈÕ¼2 bytes - public static int BufferSize = 64000; // µ¥¸öЭÒé×֧³Ö64000×Ö½Ú£¬¼´62.5KB - public static readonly ObjectPool WriterPool = new ObjectPool(() => new MessageWriter(BufferSize)); + public static int BUFFER_SIZE = 64000; // µ¥¸öÏûÏ¢×֧³Ö64000×Ö½Ú£¬¼´62.5KB + public static readonly ObjectPool WriterPool = new ObjectPool(() => new MessageWriter(BUFFER_SIZE)); public byte[] Buffer; - public int Length; // ÓÐЧÊý¾ÝÔÚbufferÖеij¤¶È£¬¿ÉÄܰüº¬¶à¸öǶÌ××ÓЭÒé - public int Position; // дÈëλ±ê - - // ÓÐÁ½¸ölength£¬Ò»¸öÊÇÊý¾ÝÔÚ»º³åÇøÀïµÄ´óСLength£¬Ò»¸öÊÇÿ¸öЭÒé»òÕß×ÓЭÒéÊý¾Ý²¿·ÖµÄ×Ö½ÚÊý + public int Length; // ÓÐЧÊý¾ÝÔÚbufferÖеij¤¶È£¬¿ÉÄܰüº¬¶à¸öǶÌ××ÓÏûÏ¢ + public int Position; // дÈëÓαê - private Stack messageStarts = new Stack(); // ¼Ç¼µ¥¸öЭÒéÔÚbufferÖÐµÄÆðʼλÖã¬ÓÃÓÚǶÌ׽ṹ + // ÓÐÁ½¸ölength£¬Ò»¸öÊÇÊý¾ÝÔÚ»º³åÇøÀïµÄ´óСLength£¬Ò»¸öÊÇÿ¸öÏûÏ¢»òÕß×ÓÏûÏ¢Êý¾Ý²¿·ÖµÄ×Ö½ÚÊý - public MessageWriter(byte[] buffer) - { - this.Buffer = buffer; - this.Length = this.Buffer.Length; - } + private Stack messageStarts = new Stack(); // ¼Ç¼µ¥¸öÏûÏ¢ÔÚbufferÖÐµÄÆðʼλÖã¬ÓÃÓÚǶÌ׽ṹ - /// +#region ´´½¨ + /// + /// ´´½¨Ò»¸ö»º³åÇø×î´óΪָ¶¨´óСµÄMessage + /// + /// public MessageWriter(int bufferSize) { this.Buffer = new byte[bufferSize]; } - public byte[] ToByteArray() - { - byte[] output = new byte[this.Length]; - System.Buffer.BlockCopy(this.Buffer, 0, output, 0, this.Length); - return output; - } - - /// The option specifying how the message should be sent. + /// + /// ´Ó³Ø×ÓÖÐÄÃÒ»¸ö»º³åÇø´óСΪBufferSizeµÄMessage + /// + /// public static MessageWriter Get() { MessageWriter output = WriterPool.GetObject(); @@ -59,6 +53,14 @@ namespace MultiplayerToolkit return output; } +#endregion + + public byte[] ToByteArray() + { + byte[] output = new byte[this.Length]; + System.Buffer.BlockCopy(this.Buffer, 0, output, 0, this.Length); + return output; + } /// /// ÊÇ·ñÓÐexpected³¤¶ÈµÄÄÚÈÝ @@ -70,7 +72,14 @@ namespace MultiplayerToolkit return this.Length >= expected; } - /// + public bool HasBytesExactly(int exact) + { + return this.Length == exact; + } + + /// + /// ¿ªÊ¼Ð´ÈëÏûÏ¢£¬²¢Ð´Èë2bytes×÷Ϊ³¤¶È + /// public void StartMessage() { var messageStart = this.Position; @@ -78,9 +87,12 @@ namespace MultiplayerToolkit this.Buffer[messageStart] = 0; // length this.Buffer[messageStart + 1] = 0; // length this.Position += 2; // ushort length + this.Length = this.Position; } - /// + /// + /// ÉèÖôËÏûÏ¢³¤¶È£¬±êÖ¾×ÅÏûÏ¢½áÊø + /// public void EndMessage() { var lastMessageStart = messageStarts.Pop(); @@ -117,18 +129,22 @@ namespace MultiplayerToolkit #region WriteMethods + /// + /// дÈë¶ÁÈ¡µ½µÄÏûÏ¢£¬Í¨³£ÓÃÓÚ·þÎñÆ÷Êܵ½ÏûÏ¢ºóµÄ¹ã²¥ºÍת·¢¡£²»ÐèÒªStart\End + /// + /// public void CopyFrom(MessageReader target) { int offset, length; - if (target.Tag == byte.MaxValue) + if (target.IsRoot) { offset = target.Offset; length = target.Length; } else { - offset = target.Offset - 3; - length = target.Length + 3; + offset = target.Offset - 2; + length = target.Length + 2; } System.Buffer.BlockCopy(target.Buffer, offset, this.Buffer, this.Position, length); diff --git a/Projects/Message/Message/MessageWriterTests.cs b/Projects/Message/Message/MessageWriterTests.cs new file mode 100644 index 0000000..9a873a5 --- /dev/null +++ b/Projects/Message/Message/MessageWriterTests.cs @@ -0,0 +1,260 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + + +namespace MultiplayerToolkit +{ + + [TestClass] + public class MessageWriterTests + { + + [TestMethod] + public void HasBytesExactly() + { + var msg = new MessageWriter(128); + + msg.StartMessage(); + Assert.IsTrue(msg.HasBytesExactly(2)); + msg.Write((int)32); + Assert.IsTrue(msg.HasBytesExactly(6)); + msg.EndMessage(); + + msg.StartMessage(); + Assert.IsTrue(msg.HasBytesExactly(8)); + msg.Write((short)2); + Assert.IsTrue(msg.HasBytesExactly(10)); + msg.EndMessage(); + Assert.IsTrue(msg.HasBytesExactly(10)); + } + + [TestMethod] + public void HasBytesExactlyNest() + { + var msg = new MessageWriter(128); + + msg.StartMessage(); + Assert.IsTrue(msg.HasBytesExactly(2)); + msg.Write((int)32); + Assert.IsTrue(msg.HasBytesExactly(6)); + //msg.EndMessage(); + + msg.StartMessage(); + Assert.IsTrue(msg.HasBytesExactly(8)); + msg.Write((short)2); + Assert.IsTrue(msg.HasBytesExactly(10)); + msg.EndMessage(); + msg.EndMessage(); + Assert.IsTrue(msg.HasBytesExactly(10)); + } + + [TestMethod] + public void HasBytesExactlyGet() + { + var msg = MessageWriter.Get(); + + msg.StartMessage(); + Assert.IsTrue(msg.HasBytesExactly(2)); + msg.Write((int)32); + Assert.IsTrue(msg.HasBytesExactly(6)); + msg.EndMessage(); + + msg.StartMessage(); + Assert.IsTrue(msg.HasBytesExactly(8)); + msg.Write((short)2); + Assert.IsTrue(msg.HasBytesExactly(10)); + msg.EndMessage(); + Assert.IsTrue(msg.HasBytesExactly(10)); + } + + [TestMethod] + public void CancelMessages() + { + var msg = new MessageWriter(128); + + msg.StartMessage(); + msg.Write(32); + + msg.StartMessage(); + msg.Write(2); + msg.CancelMessage(); + + Assert.AreEqual(6, msg.Length); + Assert.IsTrue(msg.HasBytes(6)); + + msg.CancelMessage(); + + Assert.AreEqual(0, msg.Length); + Assert.IsFalse(msg.HasBytes(1)); + } + + + [TestMethod] + public void WriteProperInt() + { + const int Test1 = int.MaxValue; + const int Test2 = int.MinValue; + + var msg = new MessageWriter(128); + msg.Write(Test1); + msg.Write(Test2); + + Assert.AreEqual(8, msg.Length); + Assert.AreEqual(msg.Length, msg.Position); + + using (MemoryStream m = new MemoryStream(msg.Buffer, 0, msg.Length)) + using (BinaryReader reader = new BinaryReader(m)) + { + Assert.AreEqual(Test1, reader.ReadInt32()); + Assert.AreEqual(Test2, reader.ReadInt32()); + } + } + + [TestMethod] + public void WriteProperBool() + { + const bool Test1 = true; + const bool Test2 = false; + + var msg = new MessageWriter(128); + msg.Write(Test1); + msg.Write(Test2); + + Assert.AreEqual(2, msg.Length); + Assert.AreEqual(msg.Length, msg.Position); + + using (MemoryStream m = new MemoryStream(msg.Buffer, 0, msg.Length)) + using (BinaryReader reader = new BinaryReader(m)) + { + Assert.AreEqual(Test1, reader.ReadBoolean()); + Assert.AreEqual(Test2, reader.ReadBoolean()); + } + } + + [TestMethod] + public void WriteProperString() + { + const string Test1 = "Hello"; + string Test2 = new string(' ', 1024); + var msg = new MessageWriter(2048); + msg.Write(Test1); + msg.Write(Test2); + msg.Write(string.Empty); + + Assert.AreEqual(msg.Length, msg.Position); + + using (MemoryStream m = new MemoryStream(msg.Buffer, 0, msg.Length)) + using (BinaryReader reader = new BinaryReader(m)) + { + Assert.AreEqual(Test1, reader.ReadString()); + Assert.AreEqual(Test2, reader.ReadString()); + Assert.AreEqual(string.Empty, reader.ReadString()); + } + } + + [TestMethod] + public void WriteProperFloat() + { + const float Test1 = 12.34f; + + var msg = new MessageWriter(2048); + msg.Write(Test1); + + Assert.AreEqual(msg.Length, msg.Position); + + using (MemoryStream m = new MemoryStream(msg.Buffer, 0, msg.Length)) + using (BinaryReader reader = new BinaryReader(m)) + { + Assert.AreEqual(Test1, reader.ReadSingle()); + } + } + + [TestMethod] + public void WritePackedUint() + { + var msg = new MessageWriter(2048); + msg.StartMessage(); + msg.WritePacked(8u); + msg.WritePacked(250u); + msg.WritePacked(68000u); + msg.EndMessage(); + + Assert.AreEqual(2 + 1 + 2 + 3, msg.Position); + Assert.AreEqual(msg.Length, msg.Position); + + MessageReader reader = MessageReader.GetChildMessage(msg.Buffer, 0); + + Assert.AreEqual(8u, reader.ReadPackedUInt32()); + Assert.AreEqual(250u, reader.ReadPackedUInt32()); + Assert.AreEqual(68000u, reader.ReadPackedUInt32()); + } + + [TestMethod] + public void WritePackedInt() + { + var msg = new MessageWriter(2048); + msg.StartMessage(); + msg.WritePacked(8); + msg.WritePacked(250); + msg.WritePacked(68000); + msg.WritePacked(60168000); + msg.WritePacked(-68000); + msg.WritePacked(-250); + msg.WritePacked(-8); + + msg.WritePacked(0); + msg.WritePacked(-1); + msg.WritePacked(int.MinValue); + msg.WritePacked(int.MaxValue); + msg.EndMessage(); + + Assert.AreEqual(2 + 1 + 2 + 3 + 4 + 5 + 5 + 5 + 1 + 5 + 5 + 5, msg.Position); + Assert.AreEqual(msg.Length, msg.Position); + + MessageReader reader = MessageReader.GetChildMessage(msg.Buffer, 0); + + Assert.AreEqual(8, reader.ReadPackedInt32()); + Assert.AreEqual(250, reader.ReadPackedInt32()); + Assert.AreEqual(68000, reader.ReadPackedInt32()); + Assert.AreEqual(60168000, reader.ReadPackedInt32()); + + Assert.AreEqual(-68000, reader.ReadPackedInt32()); + Assert.AreEqual(-250, reader.ReadPackedInt32()); + Assert.AreEqual(-8, reader.ReadPackedInt32()); + + Assert.AreEqual(0, reader.ReadPackedInt32()); + Assert.AreEqual(-1, reader.ReadPackedInt32()); + Assert.AreEqual(int.MinValue, reader.ReadPackedInt32()); + Assert.AreEqual(int.MaxValue, reader.ReadPackedInt32()); + } + + [TestMethod] + public void WritesMessageLength() + { + var msg = new MessageWriter(2048); + msg.StartMessage(); + msg.Write(65534); + msg.EndMessage(); + + Assert.AreEqual(2 + 4, msg.Position); + Assert.AreEqual(msg.Length, msg.Position); + + using (MemoryStream m = new MemoryStream(msg.Buffer, 0, msg.Length)) + using (BinaryReader reader = new BinaryReader(m)) + { + Assert.AreEqual(4, reader.ReadUInt16()); // Length After Type and Target + Assert.AreEqual(65534, reader.ReadInt32()); // Content + } + } + + [TestMethod] + public void GetLittleEndian() + { + Assert.IsTrue(MessageWriter.IsLittleEndian()); + } + + } +} \ No newline at end of file diff --git a/Projects/Message/Message/Properties/Settings.Designer.cs b/Projects/Message/Message/Properties/Settings.Designer.cs new file mode 100644 index 0000000..47da87d --- /dev/null +++ b/Projects/Message/Message/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// 此代ç �由工具生æˆ�。 +// è¿�行时版本:4.0.30319.42000 +// +// 对此文件的更改å�¯èƒ½ä¼šå¯¼è‡´ä¸�正确的行为,并且如果 +// é‡�新生æˆ�代ç �,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace Message.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/Projects/Message/Message/Properties/Settings.settings b/Projects/Message/Message/Properties/Settings.settings new file mode 100644 index 0000000..049245f --- /dev/null +++ b/Projects/Message/Message/Properties/Settings.settings @@ -0,0 +1,6 @@ + + + + + + diff --git a/Projects/Message/Message/UnitTest1.cs b/Projects/Message/Message/UnitTest1.cs deleted file mode 100644 index 2e02c6e..0000000 --- a/Projects/Message/Message/UnitTest1.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; - -namespace Message -{ - [TestClass] - public class UnitTest1 - { - [TestMethod] - public void TestMethod1() - { - - Assert.AreEqual(1, 1); - } - } -} diff --git a/Tools/Hazel-Networking/Hazel/MessageReader.cs b/Tools/Hazel-Networking/Hazel/MessageReader.cs index b6e35de..ab088df 100644 --- a/Tools/Hazel-Networking/Hazel/MessageReader.cs +++ b/Tools/Hazel-Networking/Hazel/MessageReader.cs @@ -88,11 +88,7 @@ namespace Hazel return output; } - /// - /// 完全å¤�制 一份 - /// - /// - /// + // 没用 public static MessageReader Get(MessageReader source) { var output = MessageReader.GetSized(source.Buffer.Length); @@ -181,12 +177,13 @@ namespace Hazel return output; } - public MessageWriter StartWriter() - { - var output = new MessageWriter(this.Buffer); - output.Position = this.readHead; - return output; - } + // 没用,注释掉了 + //public MessageWriter StartWriter() + //{ + // var output = new MessageWriter(this.Buffer); + // output.Position = this.readHead; + // return output; + //} public MessageReader Duplicate() { diff --git a/Tools/Hazel-Networking/Hazel/MessageWriter.cs b/Tools/Hazel-Networking/Hazel/MessageWriter.cs index 68280cd..a156c77 100644 --- a/Tools/Hazel-Networking/Hazel/MessageWriter.cs +++ b/Tools/Hazel-Networking/Hazel/MessageWriter.cs @@ -24,18 +24,19 @@ namespace Hazel public static readonly ObjectPool WriterPool = new ObjectPool(() => new MessageWriter(BufferSize)); public byte[] Buffer; // 缓冲区,ä¿�存了整个包体,包括头部和内容 - public int Length; // 有效数æ�®åœ¨buffer中的长度,å�¯èƒ½åŒ…å�«å¤šä¸ªåµŒå¥—å­�å��议。Length>=Position + public int Length; // 有效数æ�®åœ¨buffer中的长度,包å�«header,å�¯èƒ½åŒ…å�«å¤šä¸ªåµŒå¥—å­�å��议。Length>=Position public int Position; // 写入游标 public SendOption SendOption { get; private set; } private Stack messageStarts = new Stack(); - public MessageWriter(byte[] buffer) - { - this.Buffer = buffer; - this.Length = this.Buffer.Length; - } + // 没用,注释掉了 + //public MessageWriter(byte[] buffer) + //{ + // this.Buffer = buffer; + // this.Length = this.Buffer.Length; + //} /// public MessageWriter(int bufferSize) @@ -98,10 +99,10 @@ namespace Hazel { if (this.SendOption == SendOption.None) { - return this.Length > 1 + expected; + return this.Length > 1 + expected; // header=1 byte } - return this.Length > 3 + expected; + return this.Length > 3 + expected; // header=3 bytes } /// @@ -109,9 +110,10 @@ namespace Hazel { var messageStart = this.Position; messageStarts.Push(messageStart); - this.Buffer[messageStart] = 0; // + this.Buffer[messageStart] = 0; // length this.Buffer[messageStart + 1] = 0; this.Position += 2; + //this.Length = this.Position; this.Write(typeFlag); } @@ -131,6 +133,10 @@ namespace Hazel this.Length = this.Position; } + /// + /// é‡�置为sendOption类型的空包 + /// + /// public void Clear(SendOption sendOption) { Array.Clear(this.Buffer, 0, this.Buffer.Length);//完全清空整个缓冲区 -- cgit v1.1-26-g67d0