Linux(二十七)TCP的粘包問題

TCP面向字節流

創建一個TCP的socket,同時在內核中創建一個發送緩衝區和一個接收緩衝區
*調用write,數據會先寫入發送緩衝區中;
*如果發送的字節數太長,會被拆分成多個TCP的數據包發出;
*如果發送的字節數太短,就會現在緩衝區裏等着,等到緩衝區長度差不多了,或者其他合適的時機發送出去;
接收數據的時候,數據也是從網卡驅動程序到達內核的接收緩衝區;
然後應用程序可以調用read從接收緩衝區中拿數據;
另一方面,TCP的一個連接,既有發送緩衝區,也有接收緩衝區,那麼對於這樣一個連接,既可以讀數據,也可以寫數據,這個概念叫做全雙工。

由於緩衝區的存在,TCP程序的讀和寫不需要一一匹配
*寫一百個數據時,可以調用一次write寫100個字節,也可以調用100次write,一次寫一個字節;
*讀一百個數據時,也完全不需要烤爐寫的時候是怎麼寫的,既可以一次read100個字節,也可以一次read一個字節,read100次

粘包問題

首先要明確,粘包問題中的包指的是數據包
在TCP的協議頭中,沒有如同UDP一樣的報文長度這樣的字段,但是有一個序號這樣的字段。
站在傳輸層的角度,TCP是一個一個報文過來的,按照序號排好序放在緩衝區中,
站在應用層角度,看到的只是一串連續的字節數據。
那麼應用程序看到了這麼一連串的字節數據,就不知道從哪個部分開始到哪個部分,是一個完整的應用層數據包。

粘包問題的常見原因

最常見的有三種情況:
1:因爲發送數據包是,每次發的包小,因爲系統進行優化算法,就將兩次的包放在一起發送,減少了資源的重複佔用,多次發送回經歷多次網絡延遲,一起發送回減少網絡延遲的次數。因此在發送小數據時會將兩次數據一起發送,而客戶端接收時會一併接收。服務器在接收到信息,就無法區分那些數據包是客戶端自己分開發送的;

2:服務器在接收到數據後,放到緩衝區中,但是消息沒有及時從緩衝區中取走,下次再取輸的時候就可能會出現一次取出多個數據包的情況;

3:也可能受MTU,mss影響TCP在傳輸前進行拆包,出現粘包問題

那麼我們該如何避免粘包問題呢?

歸根結底就是一句話,明確兩個包之間的邊界。
*對於定長的包,保證每次都按固定大小讀取即可;
*對於變長的包,可以在包頭位置,約定一個包總長度的字段,從而就知道了包結束的位置;
對於變長的包,還可以在包與包之間使用明確的分隔符

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章