通常所謂的TCP粘包是在一次接收數據不能徹底地體現一個完整的消息數據。TCP通信爲什麼存在粘包呢?主要緣由是TCP是以流的方式來處理數據,再加上網絡上MTU的每每小於在應用處理的消息數據,因此就會引起一次接收的數據沒法知足消息的須要,致使粘包的存在。處理粘包的惟一方法就是制定應用層的數據通信協議,經過協議來規範現有接收的數據是否知足消息數據的須要。在應用中處理粘包的基礎方法主要有兩種分別是以4節字描述消息大小或以結束符,實際上也有二者相結合的如HTTP,redis的通信協議等。redis
在平時交流過程發現一些朋友即便作了這些協議的處理,但有時在處理數據的時候也會出現數據不對的狀況。這主要緣由他們在一些個別狀況下沒有處理好。由於當一系列的消息發送過來的時候,對於4節字頭或結束符分佈位置都是不肯定的。一種簡單的狀況就是當前消息處理完成後,緊接着就是處理一下個消息的4節字描述,但在實際狀況下當前接收的buffer剩下的內容有可能不足4節字的。若是你想經過通信的程序來測這狀況相對來講觸發的機率性不高,因此對於協議分析的功能最好經過單元測試來模擬。網絡
經過下面這個圖能夠更清晰地瞭解協議標記數據分佈的狀況 單元測試
下面簡單地介紹一下4字節描述大小和結束符和處理方式。測試
1 public void Import(byte[] data, int start, int count) 2 { 3 while (count > 0) 4 { 5 if (!mLoading) 6 { 7 mCheckSize.Reset(); 8 mStream.SetLength(0); 9 mStream.Position = 0; 10 mLoading = true; 11 } 12 if (mCheckSize.Length == -1) 13 { 14 while (count > 0 && mCheckSize.Length == -1) 15 { 16 mCheckSize.Import(data[start]); 17 start++; 18 count--; 19 } 20 } 21 else 22 { 23 if (OnImport(data, ref start, ref count)) 24 { 25 mLoading = false; 26 if (Receive != null) 27 { 28 mStream.Position = 0; 29 Receive(mStream); 30 } 31 } 32 } 33 } 34 } 35 36 37 public void Import(byte value) 38 { 39 LengthData[mIndex] = value; 40 if (mIndex == 3) 41 { 42 Length = BitConverter.ToInt32(LengthData, 0); 43 if (!LittleEndian) 44 Length = Endian.SwapInt32(Length); 45 } 46 else 47 { 48 mIndex++; 49 } 50 }
代碼很簡單若是沒有長度描述的狀況就把數據導入到消息長度描述的buffer中,若是當前buffer知足4位的狀況直接獲得相應長度。後面的工做就是獲取相應長度的buffer便可。spa
1 public void Import(byte[] data, int start, int count) 2 { 3 while (count > 0) 4 { 5 if (!mLoading) 6 { 7 mStream.SetLength(0); 8 mStream.Position = 0; 9 mLoading = true; 10 } 11 if (data[x] == mEof[0]) 12 { 13 start += mEof.Length; 14 count -= mEof.Length; 15 mLoading = false; 16 if (Receive != null) 17 { 18 mStream.Position = 0; 19 Receive(mStream); 20 } 21 } 22 else 23 { 24 mStream.Write(data[start]); 25 start++; 26 count--; 27 } 28 } 29 }
結束符的處理方式就相對來講簡單多了。.net
以上就是兩種TCP數據處理粘包的狀況,相關代碼緊供參考。code