1 什麼是粘包現象
TCP粘包是指發送方發送的若干包數據到接收方接收時粘成一包,從接收緩衝區看,後一包數據的頭緊接着前一包數據的尾。
2 爲什麼出現粘包現象
(1)發送方原因
我們知道,TCP默認會使用Nagle算法。而Nagle算法主要做兩件事:1)只有上一個分組得到確認,纔會發送下一個分組;2)收集多個小分組,在一個確認到來時一起發送。
所以,正是Nagle算法造成了發送方有可能造成粘包現象。
(2)接收方原因
TCP接收到分組時,並不會立刻送至應用層處理,或者說,應用層並不一定會立即處理;實際上,TCP將收到的分組保存至接收緩存裏,然後應用程序主動從緩存裏讀收到的分組。這樣一來,如果TCP接收分組的速度大於應用程序讀分組的速度,多個包就會被存至緩存,應用程序讀時,就會讀到多個首尾相接粘到一起的包。
3 什麼時候需要處理粘包現象
(1)如果發送方發送的多個分組本來就是同一個數據的不同部分,比如一個很大的文件被分成多個分組發送,這時,當然不需要處理粘包的現象;
(2)但如果多個分組本毫不相干,甚至是並列的關係,我們就一定要處理粘包問題了。比如,我當時要接收的每個分組都是一個有固定格式的商品信息,如果不處理粘包問題,每個讀進來的分組我只會處理最前邊的那個商品,後邊的就會被丟棄。這顯然不是我要的結果。
4 如何處理粘包現象
(1)發送方
對於發送方造成的粘包現象,我們可以通過關閉Nagle算法來解決,使用TCP_NODELAY選項來關閉Nagle算法。
(2)接收方
遺憾的是TCP並沒有處理接收方粘包現象的機制,我們只能在應用層進行處理。
(3)應用層處理
應用層的處理簡單易行!並且不僅可以解決接收方造成的粘包問題,還能解決發送方造成的粘包問題。
解決方法就是循環處理:應用程序在處理從緩存讀來的分組時,讀完一條數據時,就應該循環讀下一條數據,直到所有的數據都被處理;但是如何判斷每條數據的長度呢?
兩種途徑:
1)格式化數據:每條數據有固定的格式(開始符、結束符),這種方法簡單易行,但選擇開始符和結束符的時候一定要注意每條數據的內部一定不能出現開始符或結束符;
2)發送長度:發送每條數據的時候,將數據的長度一併發送,比如可以選擇每條數據的前4位是數據的長度,應用層處理時可以根據長度來判斷每條數據的開始和結束。
完全示例:解決方案示例
3)多發一個報頭信息,在2)的基礎上,可以增加更多的數據信息
完整示例:解決方案示例
當時在做購物車的時候,我最開始的做法是設置開始符(0x7e)和結束符(0xe7),但在測試大量數據的時候,發現了數據異常。正如我所猜測,在調試過程中發現某些數據內部包含了它們。因爲要處理的數據是量非常龐大,爲做到萬無一失,最後我採用了發送長度的方式。再也沒有因爲粘包而出過問題。