public AsyncSendBufferManager(int bufferSize) { m_dynamicBufferManager = new DynamicBufferManager(bufferSize); m_sendBufferList = new List<SendBufferPacket>(); m_sendBufferPacket.Offset = 0; m_sendBufferPacket.Count = 0; }
///// <summary> ///// 收集監視器數據之命令統計開始 ///// </summary> //private void CommandStatStart() //{ // //命令當前并發數 // ServerStatistics.Concurrent_Commands++; // //命令最高并發數 // if (ServerStatistics.MaxConcurrent_Commands < ServerStatistics.Concurrent_Commands) // ServerStatistics.MaxConcurrent_Commands = ServerStatistics.Concurrent_Commands; //} ///// <summary> ///// 收集監視器數據之命令統計結束 ///// </summary> //private void CommandStatEnd(long ElapsedMilliseconds) //{ // //命令當前并發數 // ServerStatistics.Concurrent_Commands--; // //命令當前執行時長(ms) // ServerStatistics.DurationTime_Command = (int)ElapsedMilliseconds; // //命令最大執行時長(ms) // if (ServerStatistics.MaxDurationTime_Command < ServerStatistics.DurationTime_Command) // ServerStatistics.MaxDurationTime_Command = ServerStatistics.DurationTime_Command; //} /// <summary> /// 掃描所有可以發送的完整包 /// </summary> /// <param name="userToken"></param> /// <param name="receiveBuffer"></param> /// <returns></returns> private bool PreparePackages(SocketUserToken userToken, DynamicBufferManager receiveBuffer) { try { //error = false; //Test //System.Diagnostics.Debug.WriteLine("調用:PreparePackages..."); //System.Text.Encoding.UTF8.GetString(LxTcpServer.Protocol.ParseProtocol.GetByteBuffer(receiveBuffer.Buffer, 0, receiveBuffer.DataCount)).TrimEnd('\0') bool CommandResult = false; Stopwatch sw = new Stopwatch(); //判斷緩存中剩餘的數據是否足夠計算完整包 if (receiveBuffer.DataCount - m_packageOffset < MSGINFOHEAD.BodyLength) { if (m_readyPackage > 0) { //已經收集到所有可發送的完整包 //m_doProcessCommand = true; //return true; userToken.FirstPacket = true; m_packageOffset = 0; //收集監視器數據之命令統計開始 ServerStatistics.CommandStatStart(); //開始計時 sw.Start(); //開始發送 CommandResult = ProcessCommand(userToken); //結束計時 sw.Stop(); //收集監視器數據之命令統計結束 ServerStatistics.CommandStatEnd(sw.ElapsedMilliseconds); //重置計時器 sw.Reset(); return CommandResult; } else { //繼續收 return true; } } int DataLen = 0; // #Mark 5# <-不要刪除這個標記!! //1.包體長度(16進制轉10進制) byte[] DataLenBuffer = ParseProtocol.GetByteBuffer(receiveBuffer.Buffer, m_packageOffset, MSGINFOHEAD.BodyLength); try { DataLen = ParseProtocol.Convert16To10(Encoding.UTF8.GetString(DataLenBuffer)); if (DataLen == 0) { //如果類別不是S(簽名為空),就說明數據錯誤. if (Encoding.UTF8.GetString(receiveBuffer.Buffer, m_packageOffset + MSGINFOHEAD.BodyLength, 1) != "S") { //視為異常 DataLen = -1; } } } catch { //異常 DataLen = -1; } //如果是用戶修改簽名為空白,此處就是0. //if (DataLen == 0) if (DataLen < 0) { //if (userToken.BindingUser != null && userToken.ConnectSocket != null && userToken.ConnectSocket.Connected) //{ // #region " 沒找到出錯原因,暫時特殊處理一下 " // try // { // if (m_packageOffset == 1026 && !userToken.FirstPacket && receiveBuffer.DataCount == 1056) // { // //先針對1026 - 1056的錯誤特別處理一下 // //錯誤描述:客戶端:D026533信息異常,包頭: 的長度小於0. PackageOffset:1026.FirstPackage:False. // // 完整信息(Bytes:1056):00016D026533 // //修正 PackageOffset 和 FirstPackage // m_packageOffset = 0; // userToken.FirstPacket = true; // DataLen = 1; // string msg = Encoding.UTF8.GetString(receiveBuffer.Buffer, 0, receiveBuffer.DataCount); // LogHelper.WriteLog("BaseProcessor.PreparePackages", "發生1026-1056錯誤,數據已修正." + "\r\n完整信息(緩存Bytes:" + receiveBuffer.DataCount.ToString() + ",取出數據實際長度:" + msg.Length.ToString() + "):" + msg); // } // else if (m_packageOffset == 5121 && !userToken.FirstPacket && receiveBuffer.DataCount == 5131) // { // //先針對5121 - 5131的錯誤特別處理一下 ==>> 這個問題已經解了:因為未對簽名為空的情況進行處理,數據總長應該加上尾包長度,再去移除) <<== // //錯誤描述:客戶端:D037198信息異常,包頭: 的長度小於0. PackageOffset:5121.FirstPackage:False. // // 完整信息(Bytes:5131):100016D037198 // //將第一位無效數據移除 // receiveBuffer.Clear(1); // //修正 PackageOffset 和 FirstPackage // m_packageOffset = 0; // userToken.FirstPacket = true; // DataLen = 1; // string msg = Encoding.UTF8.GetString(receiveBuffer.Buffer, 0, receiveBuffer.DataCount); // LogHelper.WriteLog("BaseProcessor.PreparePackages", "發生5121-5131錯誤,數據已修正." + "\r\n完整信息(緩存Bytes:" + receiveBuffer.DataCount.ToString() + ",取出數據實際長度:" + msg.Length.ToString() + "):" + msg); // } // } // catch(Exception ex) // { // LogHelper.WriteLog("BaseProcessor.PreparePackages", "嘗試修正數據時出錯:" + ex.Message); // return false; // } // #endregion //} //else //{ if (userToken.BindingUser != null) LogHelper.WriteLog("BaseProcessor.PreparePackages", "客戶端:" + userToken.BindingUser.ID + "信息異常,包頭:" + Encoding.UTF8.GetString(DataLenBuffer) + "的長度小於0. PackageOffset:" + m_packageOffset.ToString() + ".FirstPackage:" + userToken.FirstPacket.ToString() + ".\r\n完整信息(Bytes:" + receiveBuffer.DataCount.ToString() + "):" + Encoding.UTF8.GetString(receiveBuffer.Buffer, 0, receiveBuffer.DataCount)); //.TrimEnd('\0') else LogHelper.WriteLog("BaseProcessor.PreparePackages", "UserToken.BindingUser為空.信息異常,包頭:" + Encoding.UTF8.GetString(DataLenBuffer) + "的長度小於0.");//.TrimEnd('\0') return false; //} } //$Mark 1$ <-不要刪除這個標記!! //包頭+包體+包尾長度比當前已經收到的長度大.(需要加上包頭和包尾的長度) if (ParseProtocol.GetHeadPacketLength(userToken.FirstPacket) + DataLen + MSGINFOEND.EofLength + m_packageOffset > receiveBuffer.DataCount) { if (m_readyPackage > 0) { //已經收集到所有可發送的完整包 //m_doProcessCommand = true; //return true; userToken.FirstPacket = true; m_packageOffset = 0; //收集監視器數據之命令統計開始 ServerStatistics.CommandStatStart(); //開始計時 sw.Start(); //開始發送 CommandResult = ProcessCommand(userToken); //結束計時 sw.Stop(); //收集監視器數據之命令統計結束 ServerStatistics.CommandStatEnd(sw.ElapsedMilliseconds); //重置計時器 sw.Reset(); return CommandResult; } else { //如果有續包就讀取完成再解包 //==================================================================================== //====== 以下是分析為什麼偶爾出現心跳包解包錯誤,而m_packageOffset永遠是6的問題 ======= //心跳標準長1024+1+1,如果此時receiveBuffer.DataCount沒收足夠(假設只收了1024).就會運行到這里. //此時如果把FirstPacket標記為false并再次接收,就會進入 #Mark 1# 處. //按下來m_packageOffset會被賦值為4+1+1,那麼tailData必然不是1,就進入 #Mark 2# //因為之前一個完整包都沒收到,所以m_readyPackage是0,必然進入 #Mark 3# //接下來按FirstPacket為false計算數據包標準長并與receiveBuffer.DataCount比效后,必然進入 #Mark 4# //至此,m_packageOffset變成了6,執行 #Mark 5# 時就報錯了. //==================================================================================== //userToken.FirstPacket = false; //解決方案: if (ParseProtocol.GetHeadPacketLength(userToken.FirstPacket) + DataLen + MSGINFOEND.EofLength > receiveBuffer.DataCount) { //目前收到的包還不夠一個標準包長,那就視為是首包 userToken.FirstPacket = true; } else { //目前收到的包超過了一個標準包長,那就視為是續包 userToken.FirstPacket = false; } return true; } } else { // #Mark 1# <-不要刪除這個標記!! //收取完整,開始分析是否是完全數據(尾包為1) //記錄下一個包的起始位置 m_packageOffset += ParseProtocol.GetHeadPacketLength(userToken.FirstPacket) + DataLen + MSGINFOEND.EofLength; string tailData = Encoding.UTF8.GetString(userToken.ReceiveBuffer.Buffer, m_packageOffset - MSGINFOEND.EofLength, MSGINFOEND.EofLength).TrimEnd('\0'); if (tailData == "1") { //當前包收取結束 //Test //System.Diagnostics.Debug.WriteLine("發出:" + m_packageLength.ToString()); //System.Diagnostics.Debug.WriteLine("Buffer Total:" + receiveBuffer.DataCount.ToString()); //收好了(至少有一個完整的包可以發送),開始解包并處理命令 userToken.FirstPacket = true; //累計待發送的包個數(由ProcessCommand清除) m_readyPackage++; //後面達不到最小包長度就放棄掃描 DataLen = 1; if (ParseProtocol.GetHeadPacketLength(userToken.FirstPacket) + DataLen + MSGINFOEND.EofLength + m_packageOffset > receiveBuffer.DataCount) { //m_doProcessCommand = true; m_packageOffset = 0; //收集監視器數據之命令統計開始 ServerStatistics.CommandStatStart(); //開始計時 sw.Start(); //開始發送 CommandResult = ProcessCommand(userToken); //結束計時 sw.Stop(); //收集監視器數據之命令統計結束 ServerStatistics.CommandStatEnd(sw.ElapsedMilliseconds); //重置計時器 sw.Reset(); return CommandResult; } else { //Test //LogHelper.WriteLog("BaseProcessor.PreparePackages", "尾包值為1(位置:" + (m_packageOffset - 1).ToString() + "),FirstPacket:" + userToken.FirstPacket.ToString() + ",下次將從" + m_packageOffset.ToString() + "開始檢查首包長度.\r\n完整信息(Bytes:" + receiveBuffer.DataCount.ToString() + "):" + Encoding.UTF8.GetString(receiveBuffer.Buffer, 0, receiveBuffer.DataCount).TrimEnd('\0')); //再掃描一次(不用再去接收) return PreparePackages(userToken, receiveBuffer); } } else { // #Mark 2# <-不要刪除這個標記!! //接下來的一個包一定是續包 userToken.FirstPacket = false; if (m_readyPackage > 0) { //雖然是續包,已經收集到所有可發送的完整包,剩下來的數據0位置就是首包 userToken.FirstPacket = true;//<-- 2016/04/20 19:51 被1029問題坑得發瘋的時候加的,之前這句沒加... //=============================== 以下是1029錯誤的故事 =============================== //如果這里不賦為true,那麼m_packageOffset被置0后執行ProcessCommand,完成后執行到 #Mark 1#, //然后m_packageOffset會被設置為1029(4+1024+1), 隨後來到 #Mark 2#, 最後 #Mark 3#. 無論此處走哪邊, //都會重新進入PreparePackages,並且此時m_packageOffset為1029,userToken.FirstPacket為false. //但Buffer剩下的卻是一個以首包開始完整數據,結果崩壞! //==================================================================================== m_packageOffset = 0; //收集監視器數據之命令統計開始 ServerStatistics.CommandStatStart(); //開始計時 sw.Start(); //開始發送 CommandResult = ProcessCommand(userToken); //結束計時 sw.Stop(); //收集監視器數據之命令統計結束 ServerStatistics.CommandStatEnd(sw.ElapsedMilliseconds); //重置計時器 sw.Reset(); return CommandResult; } else { // #Mark 3# <-不要刪除這個標記!! //如果剩餘已接收數據還可以檢查一次就直接比較 DataLen = 1; if (ParseProtocol.GetHeadPacketLength(userToken.FirstPacket) + DataLen + MSGINFOEND.EofLength + m_packageOffset <= receiveBuffer.DataCount) { // #Mark 4# <-不要刪除這個標記!! return PreparePackages(userToken, receiveBuffer); } else { //繼續接收數據(有效位置就從m_packageOffset開始) return true; } } } } } catch { //error = true; //主動關閉連接 //userToken.Closing = true; return false; } }
public SocketUserToken(int receiveBufferSize) { m_connectSocket = null; m_asyncSendAgent = null; m_receiveEventArgs = new SocketAsyncEventArgs(); m_receiveEventArgs.UserToken = this; m_asyncReceiveBuffer = new byte[receiveBufferSize]; m_receiveEventArgs.SetBuffer(m_asyncReceiveBuffer, 0, m_asyncReceiveBuffer.Length); m_sendEventArgs = new SocketAsyncEventArgs(); m_sendEventArgs.UserToken = this; m_receiveBuffer = new DynamicBufferManager(ServerConst.InitBufferSize); m_sendBuffer = new AsyncSendBufferManager(ServerConst.InitBufferSize); //存放接收到的待處理的數據 //m_receiveQueue = Queue.Synchronized(new Queue()); //0表示沒有續包 //m_restPacketLength = 0; //默認為首包 m_firstPacket = true; m_user = new Core.User(); m_closing = false; }