网络:TCP粘包问题?如何解决?
?
看面經時,看到有面試官問TCP的粘包問題。想起來研一做購物車處理數據更新時遇到粘包問題,就總結一下吧。
1 什么是粘包現象
TCP粘包是指發送方發送的若干包數據到接收方接收時粘成一包,從接收緩沖區看,后一包數據的頭緊接著前一包數據的尾。
2 為什么出現粘包現象
? ? ? ?(1)發送方原因
我們知道,TCP默認會使用Nagle算法。而Nagle算法主要做兩件事:
? ? ? ? ?1)只有上一個分組得到確認,才會發送下一個分組;? ?2)收集多個小分組,在一個確認到來時一起發送。
什么是尼格拉算法?
?
如果一個應用程序一次只產生一個字節的數據,而這一個字節的數據又要以網絡數據包的形式發送到遠端服務器,那么就很容易導致網絡由于太多的數據包而過載。1字節的有效數據每次卻需要40字節包頭的額外開銷,這種極低的有效載荷利用率極易引發網絡擁塞癱瘓。尼格拉算法的提出是為了提高網絡的利用率。
但是也會發生某種程度上的延時和數據包的粘包問題。
尼格拉算法的思想是:發送端即使還有應該發送的數據,但是如果這部分數據比較少的時候,則進行延遲發送!
該算法要求一個TCP連接上最多只能有一個未被確認的未完成的小分組,在該分組的確認到來之前不發送其他的小分組。相反,TCP收集這些少量的分組,并在確認到來之時以一個分組的形式發送出去,或者該數據是緊急數據會即時發送。這樣,就能夠減少網絡中小分組的數量,提高數據包的利用率。
算法優勢:自適應,確認到達的越快,數據發送也就越快。
TCP中的Negla算法是默認開啟的
?
?
所以,正是Nagle算法造成了發送方有可能造成粘包現象。
(2)接收方原因
TCP接收到分組時,并不會立刻送至應用層處理,或者說,應用層并不一定會立即處理;實際上,TCP將收到的分組保存至接收緩存里,然后應用程序主動從緩存里讀收到的分組。這樣一來,如果TCP接收分組的速度大于應用程序讀分組的速度,多個包就會被存至緩存,應用程序讀時,就會讀到多個首尾相接粘到一起的包。
3 什么時候需要處理粘包現象
(1)如果發送方發送的多個分組本來就是同一個數據的不同部分,比如一個很大的文件被分成多個分組發送,這時,當然不需要處理粘包的現象;
(2)但如果多個分組本毫不相干,甚至是并列的關系,我們就一定要處理粘包問題了。比如,我當時要接收的每個分組都是一個有固定格式的商品信息,如果不處理粘包問題,每個讀進來的分組我只會處理最前邊的那個商品,后邊的就會被丟棄。這顯然不是我要的結果。
4 如何處理粘包現象
(1)發送方
對于發送方造成的粘包現象,我們可以通過關閉Nagle算法來解決,使用TCP_NODELAY選項來關閉Nagle算法。
(2)接收方
遺憾的是TCP并沒有處理接收方粘包現象的機制,我們只能在應用層進行處理。
(3)應用層處理
應用層的處理簡單易行!并且不僅可以解決接收方造成的粘包問題,還能解決發送方造成的粘包問題。
解決方法就是循環處理:應用程序在處理從緩存讀來的分組時,讀完一條數據時,就應該循環讀下一條數據,直到所有的數據都被處理;
但是如何判斷每條數據的長度呢?
兩種途徑:
1)格式化數據:每條數據有固定的格式(開始符、結束符),這種方法簡單易行,但選擇開始符和結束符的時候一定要注意每條數據的內部一定不能出現開始符或結束符;
2)發送長度:發送每條數據的時候,將數據的長度一并發送,比如可以選擇每條數據的前4位是數據的長度,應用層處理時可以根據長度來判斷每條數據的開始和結束。
當時在做購物車的時候,我最開始的做法是設置開始符(0x7e)和結束符(0xe7),但在測試大量數據的時候,發現了數據異常。正如我所猜測,在調試過程中發現某些數據內部包含了它們。因為要處理的數據是量非常龐大,為做到萬無一失,最后我采用了發送長度的方式。再也沒有因為粘包而出過問題。
總結
以上是生活随笔為你收集整理的网络:TCP粘包问题?如何解决?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网络:301和302
- 下一篇: 网络:forward和redirect的