diff --git a/NetLib/HaoYueNet.ClientNetwork/IOCPMode/TcpSaeaClient.cs b/NetLib/HaoYueNet.ClientNetwork/IOCPMode/TcpSaeaClient.cs index 0d6f88d..5cae85c 100644 --- a/NetLib/HaoYueNet.ClientNetwork/IOCPMode/TcpSaeaClient.cs +++ b/NetLib/HaoYueNet.ClientNetwork/IOCPMode/TcpSaeaClient.cs @@ -1,4 +1,5 @@ //using HunterProtobufCore; +using System.Buffers; using System.IO; using System.Net; using System.Net.Sockets; @@ -364,90 +365,67 @@ namespace HaoYueNet.ClientNetwork.IOCPMode { try { - // check if the remote host closed the connection AsyncUserToken token = (AsyncUserToken)e.UserToken; if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { - //读取数据 - //byte[] data = new byte[e.BytesTransferred]; - //Array.Copy(e.Buffer, e.Offset, data, 0, e.BytesTransferred); - //lock (token.Buffer) lock (token.memoryStream) { - //token.Buffer.AddRange(data); token.memoryStream.Write(e.Buffer, e.Offset, e.BytesTransferred); do { - //如果包头不完整 - //if (token.Buffer.Count < 4) - if (token.memoryStream.Length < 4) - break; - - ////判断包的长度 - //byte[] lenBytes = token.Buffer.GetRange(0, 4).ToArray(); - //int packageLen = BitConverter.ToInt32(lenBytes, 0) - 4; - //if (packageLen > token.Buffer.Count - 4) - //{ //长度不够时,退出循环,让程序继续接收 - // break; - //} - + if (token.memoryStream.Length < 4) break;//包头不完整,继续接收 long FristBeginPos = token.memoryStream.Position; - byte[] lenBytes = new byte[4]; + + //从Byte池申请 + byte[] lenBytes = ArrayPool.Shared.Rent(4); + token.memoryStream.Seek(0, SeekOrigin.Begin); token.memoryStream.Read(lenBytes, 0, 4); int packageLen = BitConverter.ToInt32(lenBytes, 0) - 4; + + //归还byte[] + ArrayPool.Shared.Return(lenBytes); + if (packageLen > token.memoryStream.Length - 4) { token.memoryStream.Seek(FristBeginPos, SeekOrigin.Begin); - //长度不够时,退出循环,让程序继续接收 - break; + break;//长度不够时,退出循环,让程序继续接收 } - ////包够长时,则提取出来,交给后面的程序去处理 - //byte[] rev = token.Buffer.GetRange(4, packageLen).ToArray(); + //申请byte池 一定要记得回收!! + byte[] rev_fromArrayPool = ArrayPool.Shared.Rent(packageLen); - byte[] rev = new byte[packageLen]; token.memoryStream.Seek(4, SeekOrigin.Begin); - token.memoryStream.Read(rev, 0, packageLen); - - //从数据池中移除这组数据 - //lock (token.Buffer) - //{ - // token.Buffer.RemoveRange(0, packageLen + 4); - //} - + token.memoryStream.Read(rev_fromArrayPool, 0, packageLen); token.memoryStream.Seek(FristBeginPos, SeekOrigin.Begin); //从数据池中移除这组数据 lock (token.memoryStream) { - //token.memoryStream.Position = 0; - //token.memoryStream.SetLength(0); int numberOfBytesToRemove = packageLen + 4; byte[] buf = token.memoryStream.GetBuffer(); Buffer.BlockCopy(buf, numberOfBytesToRemove, buf, 0, (int)token.memoryStream.Length - numberOfBytesToRemove); token.memoryStream.SetLength(token.memoryStream.Length - numberOfBytesToRemove); } - DataCallBackReady(token, rev); + //用Span内存切片,因为来自ArrayPool的byte长度,可能大于本身申请的长度 + Span rev_span = rev_fromArrayPool; + rev_span = rev_span.Slice(0, packageLen); + DataCallBackReady(token, rev_span); - //这里API处理完后,并没有返回结果,当然结果是要返回的,却不是在这里, 这里的代码只管接收. - //若要返回结果,可在API处理中调用此类对象的SendMessage方法,统一打包发送.不要被微软的示例给迷惑了. - //} while (token.Buffer.Count > 4); + //回收(这里依赖DataCallBackReady中,有一次数据拷贝,这个后续还要进一步精进性能优化,否则不能在这里回收,否则影响业务层) + ArrayPool.Shared.Return(rev_fromArrayPool); } while (token.memoryStream.Length > 4); } - //继续接收. 为什么要这么写,请看Socket.ReceiveAsync方法的说明 + //如果返回为False则代表此刻已经完成,不必等待完成端口回调,则直接调用ProcessReceive if (!token.Socket.ReceiveAsync(e)) - { - ProcessReceive(e); - } + this.ProcessReceive(e); } else { - //尝试性,清理数据 + //清理数据 token.memoryStream.SetLength(0); token.memoryStream.Seek(0, SeekOrigin.Begin); - CloseClientSocket(e); } } @@ -642,7 +620,7 @@ namespace HaoYueNet.ClientNetwork.IOCPMode #endregion #region 处理前预备 - private void DataCallBackReady(AsyncUserToken sk, byte[] data) + private void DataCallBackReady(AsyncUserToken sk, Span data) { //增加接收计数 sk.RevIndex = MaxRevIndexNum; diff --git a/NetLib/HaoYueNet.ClientNetwork/NetworkHelperCore.cs b/NetLib/HaoYueNet.ClientNetwork/NetworkHelperCore.cs index 02dea8a..8648f3a 100644 --- a/NetLib/HaoYueNet.ClientNetwork/NetworkHelperCore.cs +++ b/NetLib/HaoYueNet.ClientNetwork/NetworkHelperCore.cs @@ -257,8 +257,8 @@ namespace HaoYueNet.ClientNetwork OnReceiveData(CmdID, Error, resultdata); } - MemoryStream reciveMemoryStream = new MemoryStream();//开辟一个内存流 - byte[] reciveBuffer = new byte[1024 * 1024 * 2]; + MemoryStream reciveMemoryStream = new MemoryStream();//开辟一个反复使用的内存流 + byte[] reciveBuffer = new byte[1024 * 1024 * 2];//开辟一个反复使用的byte[] private void Recive(object o) { var client = o as Socket; @@ -312,12 +312,6 @@ namespace HaoYueNet.ClientNetwork //↓↓↓↓↓↓↓↓ ↓↓↓ if (getData.Length - StartIndex < HeadLength || HeadLength == -1) { - /* 一种清空流的方式 - memoryStream.Close();//关闭内存流 - memoryStream.Dispose();//释放内存资源 - memoryStream = new MemoryStream();//创建新的内存流 - */ - //流复用的方式 不用重新new申请 reciveMemoryStream.Position = 0; reciveMemoryStream.SetLength(0); @@ -327,16 +321,7 @@ namespace HaoYueNet.ClientNetwork } else { - //把头去掉,就可以吃了,蛋白质是牛肉的六倍 - //DataCallBackReady(getData.Skip(StartIndex+4).Take(HeadLength-4).ToArray()); - int CoreLenght = HeadLength - 4; - - //改为Array.Copy 提升效率 - //byte[] retData = new byte[CoreLenght]; - //Array.Copy(getData, StartIndex + 4, retData, 0, CoreLenght); - //DataCallBackReady(retData); - //用Span Span getData_span = getData; getData_span = getData_span.Slice(StartIndex + 4, CoreLenght); diff --git a/NetLib/HaoYueNet.ClientNetwork/NetworkHelperP2PCore.cs b/NetLib/HaoYueNet.ClientNetwork/NetworkHelperP2PCore.cs index 05374e5..7dab00d 100644 --- a/NetLib/HaoYueNet.ClientNetwork/NetworkHelperP2PCore.cs +++ b/NetLib/HaoYueNet.ClientNetwork/NetworkHelperP2PCore.cs @@ -182,24 +182,6 @@ namespace HaoYueNet.ClientNetwork /// public event delegate_str OnLogOut; - ///// - ///// 用于调用者回调的虚函数 - ///// - ///// - //public virtual void DataCallBack(int CMDID,int ERRCODE,byte[] data) - //{ - - //} - - ///// - ///// 断开连接 - ///// - ///// - //public virtual void OnClose() - //{ - - //} - /// /// 做好处理的连接管理 /// @@ -236,16 +218,12 @@ namespace HaoYueNet.ClientNetwork return; } - /* - HunterNet_S2C _c2s = DeSerizlize(data); - OnDataCallBack(_c2s.HunterNetCoreCmdID, _c2s.HunterNetCoreERRORCode, _c2s.HunterNetCoreData.ToArray()); - */ HunterNet_S2C.AnalysisPkgData(data, out ushort CmdID, out ushort Error, out byte[] resultdata); OnDataCallBack(CmdID, Error, resultdata); } - MemoryStream reciveMemoryStream = new MemoryStream();//开辟一个内存流 - byte[] reciveBuffer = new byte[1024 * 1024 * 2]; + MemoryStream reciveMemoryStream = new MemoryStream();//开辟一个反复使用的内存流 + byte[] reciveBuffer = new byte[1024 * 1024 * 2];//开辟一个反复使用的byte[] private void Recive(object o) { var client = o as Socket; @@ -299,12 +277,6 @@ namespace HaoYueNet.ClientNetwork //↓↓↓↓↓↓↓↓ ↓↓↓ if (getData.Length - StartIndex < HeadLength || HeadLength == -1) { - /* 一种清空流的方式 - memoryStream.Close();//关闭内存流 - memoryStream.Dispose();//释放内存资源 - memoryStream = new MemoryStream();//创建新的内存流 - */ - //流复用的方式 不用重新new申请 reciveMemoryStream.Position = 0; reciveMemoryStream.SetLength(0); @@ -314,16 +286,8 @@ namespace HaoYueNet.ClientNetwork } else { - //把头去掉,就可以吃了,蛋白质是牛肉的六倍 - //DataCallBackReady(getData.Skip(StartIndex+4).Take(HeadLength-4).ToArray()); - int CoreLenght = HeadLength - 4; - //改为Array.Copy 提升效率 - //byte[] retData = new byte[CoreLenght]; - //Array.Copy(getData, StartIndex + 4, retData, 0, CoreLenght); - //DataCallBackReady(retData); - //用Span Span getData_span = getData; getData_span = getData_span.Slice(StartIndex + 4, CoreLenght); diff --git a/NetLib/HaoYueNet.ClientNetwork/OtherMode/NetworkHelperCore_ListenerMode.cs b/NetLib/HaoYueNet.ClientNetwork/OtherMode/NetworkHelperCore_ListenerMode.cs index 10d359b..6f37465 100644 --- a/NetLib/HaoYueNet.ClientNetwork/OtherMode/NetworkHelperCore_ListenerMode.cs +++ b/NetLib/HaoYueNet.ClientNetwork/OtherMode/NetworkHelperCore_ListenerMode.cs @@ -1,4 +1,5 @@ -using System.Net; +using System.Buffers; +using System.Net; using System.Net.Sockets; using static HaoYueNet.ClientNetwork.BaseData; @@ -190,17 +191,20 @@ namespace HaoYueNet.ClientNetwork.OtherMode } MemoryStream reciveMemoryStream = new MemoryStream();//开辟一个内存流 - byte[] reciveBuffer = new byte[1024 * 1024 * 2]; + //byte[] reciveBuffer = new byte[1024 * 1024 * 2]; private void Recive(object o) { var client = o as Socket; while (true) { + //申请byte池 一定要记得回收!! + byte[] rev_fromArrayPool = ArrayPool.Shared.Rent(1024 * 1024 * 2); + int effective = 0; try { - effective = client.Receive(reciveBuffer); + effective = client.Receive(rev_fromArrayPool); if (effective == 0)//为0表示已经断开连接,放到后面处理 { //清理数据 @@ -208,6 +212,8 @@ namespace HaoYueNet.ClientNetwork.OtherMode reciveMemoryStream.Seek(0, SeekOrigin.Begin); //远程主机强迫关闭了一个现有的连接 OnCloseReady(client); + //回收 + ArrayPool.Shared.Return(rev_fromArrayPool); return; } } @@ -223,7 +229,11 @@ namespace HaoYueNet.ClientNetwork.OtherMode //断开连接 } - reciveMemoryStream.Write(reciveBuffer, 0, effective);//将接受到的数据写入内存流中 + reciveMemoryStream.Write(rev_fromArrayPool, 0, effective);//将接受到的数据写入内存流中 + + //回收 + ArrayPool.Shared.Return(rev_fromArrayPool); + DataCallBackReady(client, reciveMemoryStream.ToArray()); //流复用的方式 不用重新new申请 reciveMemoryStream.Position = 0; diff --git a/NetLib/HaoYueNet.ClientNetwork/OtherMode/NetworkHelperCore_SourceMode.cs b/NetLib/HaoYueNet.ClientNetwork/OtherMode/NetworkHelperCore_SourceMode.cs index a5a5884..754f1a5 100644 --- a/NetLib/HaoYueNet.ClientNetwork/OtherMode/NetworkHelperCore_SourceMode.cs +++ b/NetLib/HaoYueNet.ClientNetwork/OtherMode/NetworkHelperCore_SourceMode.cs @@ -192,8 +192,8 @@ namespace HaoYueNet.ClientNetwork.OtherMode OnReceiveData(data); } - MemoryStream reciveMemoryStream = new MemoryStream();//开辟一个内存流 - byte[] reciveBuffer = new byte[1024 * 1024 * 2]; + MemoryStream reciveMemoryStream = new MemoryStream();//开辟一个反复使用的内存流 + byte[] reciveBuffer = new byte[1024 * 1024 * 2];//开辟一个反复使用的byte[] private void Recive(object o) { var client = o as Socket; diff --git a/NetLib/HaoYueNet.ServerNetwork/BaseData.cs b/NetLib/HaoYueNet.ServerNetwork/BaseData.cs index e7615a7..5de4c0e 100644 --- a/NetLib/HaoYueNet.ServerNetwork/BaseData.cs +++ b/NetLib/HaoYueNet.ServerNetwork/BaseData.cs @@ -1,4 +1,5 @@ using System.Net.Sockets; +using System.Runtime.InteropServices; namespace HaoYueNet.ServerNetwork { @@ -142,7 +143,7 @@ namespace HaoYueNet.ServerNetwork return BufferData; } - public static void AnalysisPkgData(Span srcdata, out UInt16 CmdID, out byte[] data) + public static void AnalysisPkgData(Span srcdata,out UInt16 CmdID, out byte[] data) { //data = new byte[srcdata.Length - 2]; //CmdID = BitConverter.ToUInt16(srcdata, 0); diff --git a/NetLib/HaoYueNet.ServerNetwork/NetWork/ArrayPoolManager.cs b/NetLib/HaoYueNet.ServerNetwork/NetWork/ArrayPoolManager.cs deleted file mode 100644 index eb14139..0000000 --- a/NetLib/HaoYueNet.ServerNetwork/NetWork/ArrayPoolManager.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Buffers; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace HaoYueNet.ServerNetwork.NetWork -{ - public static class ArrayPoolManager - { - static ArrayPool instance = ArrayPool.Shared; - - /// - /// 租用指定大小byte数组 - /// - /// - /// - public static byte[] RentByteArr(int lenght) - { - return instance.Rent(lenght); - } - - - /// - /// 将数组归还给池 - /// - /// - /// - public static void ReturnByteArr(byte[] byteArr) - { - instance.Return(byteArr); - } - } -} diff --git a/NetLib/HaoYueNet.ServerNetwork/NetWork/SourceMode/TcpSaeaServer_SourceMode.cs b/NetLib/HaoYueNet.ServerNetwork/NetWork/SourceMode/TcpSaeaServer_SourceMode.cs index 4ed8553..1236617 100644 --- a/NetLib/HaoYueNet.ServerNetwork/NetWork/SourceMode/TcpSaeaServer_SourceMode.cs +++ b/NetLib/HaoYueNet.ServerNetwork/NetWork/SourceMode/TcpSaeaServer_SourceMode.cs @@ -373,51 +373,32 @@ namespace HaoYueNet.ServerNetwork { try { - // check if the remote host closed the connection AsyncUserToken token = (AsyncUserToken)e.UserToken; if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { - //读取数据 - //byte[] data = new byte[e.BytesTransferred]; - //Array.Copy(e.Buffer, e.Offset, data, 0, e.BytesTransferred); - //lock (token.Buffer) + //读取数据 lock(token.memoryStream) { - //token.Buffer.AddRange(data); token.memoryStream.Write(e.Buffer, e.Offset, e.BytesTransferred); do { - - //DataCallBackReady(token, data); - ////从数据池中移除这组数据 - //lock (token.Buffer) - //{ - // token.Buffer.Clear(); - //} - DataCallBackReady(token, token.memoryStream.ToArray()); //流复用的方式 不用重新new申请 token.memoryStream.Position = 0; token.memoryStream.SetLength(0); - //这里API处理完后,并没有返回结果,当然结果是要返回的,却不是在这里, 这里的代码只管接收. - //若要返回结果,可在API处理中调用此类对象的SendMessage方法,统一打包发送.不要被微软的示例给迷惑了. } while (token.memoryStream.Length > 0); //} while (token.Buffer.Count > 4); } - //继续接收. 为什么要这么写,请看Socket.ReceiveAsync方法的说明 if (!token.Socket.ReceiveAsync(e)) - { this.ProcessReceive(e); - } } else { //清理数据 token.memoryStream.SetLength(0); token.memoryStream.Seek(0, SeekOrigin.Begin); - CloseClientSocket(e); } } diff --git a/NetLib/HaoYueNet.ServerNetwork/NetWork/TcpSaeaServer.cs b/NetLib/HaoYueNet.ServerNetwork/NetWork/TcpSaeaServer.cs index e89b9f8..f54f5f0 100644 --- a/NetLib/HaoYueNet.ServerNetwork/NetWork/TcpSaeaServer.cs +++ b/NetLib/HaoYueNet.ServerNetwork/NetWork/TcpSaeaServer.cs @@ -1,6 +1,5 @@ //using HunterProtobufCore; -using HaoYueNet.ServerNetwork.NetWork; -using System.IO; +using System.Buffers; using System.Net; using System.Net.Sockets; using static HaoYueNet.ServerNetwork.BaseData; @@ -375,96 +374,67 @@ namespace HaoYueNet.ServerNetwork { try { - // check if the remote host closed the connection AsyncUserToken token = (AsyncUserToken)e.UserToken; if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { - //读取数据 - //byte[] data = new byte[e.BytesTransferred]; - //Array.Copy(e.Buffer, e.Offset, data, 0, e.BytesTransferred); - //lock (token.Buffer) lock(token.memoryStream) { - //token.Buffer.AddRange(data); token.memoryStream.Write(e.Buffer, e.Offset, e.BytesTransferred); do { - //如果包头不完整 - //if (token.Buffer.Count < 4) - if (token.memoryStream.Length < 4) - break; - - ////判断包的长度 - //byte[] lenBytes = token.Buffer.GetRange(0, 4).ToArray(); - //int packageLen = BitConverter.ToInt32(lenBytes, 0) - 4; - //if (packageLen > token.Buffer.Count - 4) - //{ //长度不够时,退出循环,让程序继续接收 - // break; - //} - + if (token.memoryStream.Length < 4) break;//包头不完整,继续接收 long FristBeginPos = token.memoryStream.Position; - //byte[] lenBytes = new byte[4]; - byte[] lenBytes = ArrayPoolManager.RentByteArr(4); + + //从Byte池申请 + byte[] lenBytes = ArrayPool.Shared.Rent(4); token.memoryStream.Seek(0, SeekOrigin.Begin); token.memoryStream.Read(lenBytes, 0, 4); int packageLen = BitConverter.ToInt32(lenBytes, 0) - 4; - ArrayPoolManager.ReturnByteArr(lenBytes); + //归还byte[] + ArrayPool.Shared.Return(lenBytes); if (packageLen > token.memoryStream.Length - 4) { token.memoryStream.Seek(FristBeginPos, SeekOrigin.Begin); - //长度不够时,退出循环,让程序继续接收 - break; + break;//长度不够时,退出循环,让程序继续接收 } - ////包够长时,则提取出来,交给后面的程序去处理 - //byte[] rev = token.Buffer.GetRange(4, packageLen).ToArray(); - - byte[] rev = new byte[packageLen]; - - token.memoryStream.Seek(4, SeekOrigin.Begin); - token.memoryStream.Read(rev, 0, packageLen); - - //从数据池中移除这组数据 - //lock (token.Buffer) - //{ - // token.Buffer.RemoveRange(0, packageLen + 4); - //} + //申请byte池 一定要记得回收!! + byte[] rev_fromArrayPool = ArrayPool.Shared.Rent(packageLen); + token.memoryStream.Seek(4, SeekOrigin.Begin); + token.memoryStream.Read(rev_fromArrayPool, 0, packageLen); token.memoryStream.Seek(FristBeginPos, SeekOrigin.Begin); //从数据池中移除这组数据 lock (token.memoryStream) { - //token.memoryStream.Position = 0; - //token.memoryStream.SetLength(0); int numberOfBytesToRemove = packageLen + 4; byte[] buf = token.memoryStream.GetBuffer(); Buffer.BlockCopy(buf, numberOfBytesToRemove, buf, 0, (int)token.memoryStream.Length - numberOfBytesToRemove); token.memoryStream.SetLength(token.memoryStream.Length - numberOfBytesToRemove); } - DataCallBackReady(token, rev); + //用Span内存切片,因为来自ArrayPool的byte长度,可能大于本身申请的长度 + Span rev_span = rev_fromArrayPool; + rev_span = rev_span.Slice(0, packageLen); + DataCallBackReady(token, rev_span); - //这里API处理完后,并没有返回结果,当然结果是要返回的,却不是在这里, 这里的代码只管接收. - //若要返回结果,可在API处理中调用此类对象的SendMessage方法,统一打包发送.不要被微软的示例给迷惑了. - //} while (token.Buffer.Count > 4); + //回收(这里依赖DataCallBackReady中,有一次数据拷贝,这个后续还要进一步精进性能优化,否则不能在这里回收,否则影响业务层) + ArrayPool.Shared.Return(rev_fromArrayPool); } while (token.memoryStream.Length > 4); } - //继续接收. 为什么要这么写,请看Socket.ReceiveAsync方法的说明 + //如果返回为False则代表此刻已经完成,不必等待完成端口回调,则直接调用ProcessReceive if (!token.Socket.ReceiveAsync(e)) - { this.ProcessReceive(e); - } } else { - //尝试性,清理数据 + //清理数据 token.memoryStream.SetLength(0); token.memoryStream.Seek(0, SeekOrigin.Begin); - CloseClientSocket(e); } } @@ -489,8 +459,6 @@ namespace HaoYueNet.ServerNetwork } void IO_Completed(object sender, SocketAsyncEventArgs e) { - // determine which type of operation just completed and call the associated handler - switch (e.LastOperation) { case SocketAsyncOperation.Receive: @@ -661,7 +629,7 @@ namespace HaoYueNet.ServerNetwork #endregion #region 处理前预备 - private void DataCallBackReady(AsyncUserToken sk, byte[] data) + private void DataCallBackReady(AsyncUserToken sk, Span data) { //增加接收计数 sk.RevIndex = MaxRevIndexNum; diff --git a/NetLib_Standard2/HaoYueNet.ClientNetworkNet.Standard2/NetworkHelperCore.cs b/NetLib_Standard2/HaoYueNet.ClientNetworkNet.Standard2/NetworkHelperCore.cs index b7e728d..7e21971 100644 --- a/NetLib_Standard2/HaoYueNet.ClientNetworkNet.Standard2/NetworkHelperCore.cs +++ b/NetLib_Standard2/HaoYueNet.ClientNetworkNet.Standard2/NetworkHelperCore.cs @@ -260,8 +260,9 @@ namespace HaoYueNet.ClientNetwork.Standard2 OnReceiveData(CmdID, Error, resultdata); } - MemoryStream reciveMemoryStream = new MemoryStream();//开辟一个内存流 - byte[] reciveBuffer = new byte[1024 * 1024 * 2]; + + MemoryStream reciveMemoryStream = new MemoryStream();//开辟一个反复使用的内存流 + byte[] reciveBuffer = new byte[1024 * 1024 * 2];//开辟一个反复使用的byte[] private void Recive(object o) { var client = o as Socket;