1. 程式人生 > >黏包問題的成因與解決方案

黏包問題的成因與解決方案

發送數據包 IV 內存 多次 struct 可靠 就會 maximum 讀取文件

原文鏈接地址:https://www.cnblogs.com/kakawith/p/8378425.html

一、黏包成因

tcp協議的拆包機制

當發送端緩沖區的長度大於網卡的MTU時,tcp會將這次發送的數據拆成幾個數據包發送出去。 
MTU是Maximum Transmission Unit的縮寫。意思是網絡上傳送的最大數據包。MTU的單位是字節。大部分網絡設備的MTU都是1500。
如果本機的MTU比網關的MTU大,大的數據包就會被拆開來傳送,這樣會產生很多數據包碎片,增加丟包率,降低網絡速度

面向流的通信特點和Nagle算法

技術分享圖片
TCP(transport control protocol,傳輸控制協議)是面向連接的,面向流的,提供高可靠性服務。
收發兩端(客戶端和服務器端)都要有一一成對的socket,因此,發送端為了將多個發往接收端的包,更有效的發到對方,使用了優化方法(Nagle算法),將多次間隔較小且數據量小的數據,合並成一個大的數據塊,然後進行封包。
這樣,接收端,就難於分辨出來了,必須提供科學的拆包機制。 即面向流的通信是無消息保護邊界的。 
對於空消息:tcp是基於數據流的,於是收發的消息不能為空,這就需要在客戶端和服務端都添加空消息的處理機制,防止程序卡住,而udp是基於數據報的,即便是你輸入的是空內容(直接回車),也可以被發送,udp協議會幫你封裝上消息頭發送過去。 
可靠黏包的tcp協議:tcp的協議數據不會丟,沒有收完包,下次接收,會繼續上次繼續接收,己端總是在收到ack時才會清除緩沖區內容。數據是可靠的,但是會粘包。
技術分享圖片

總結:

黏包有兩種:

一種是因為發送數據包時,每次發送的包小,因為系統進行優化算法,就將兩次的包放在一起發送,減少了資源的重復占用。多次發送會經歷多次網絡延遲,一起發送會減少網絡延遲的次數。因此在發送小數據時會將兩次數據一起發送,而客戶端接收時,則會一並接收。#即出現多次send會出現黏包

第二種是因為接收數據時,又多次接收,第一次接收的數據量小,導致數據還沒接收完,就停下了,剩余的數據會緩存在內存中,然後等到下次接收時和下一波數據一起接收。

二、黏包的解決方案

1,問題的根源在於,接收端不知道發送端將要傳送的字節流的長度,所以解決粘包的方法就是圍繞,如何讓發送端在發送數據前,把自己將要發送的字節流總大小讓接收端知曉,然後接收端來一個死循環接收完所有數據。

技術分享圖片

技術分享圖片server 技術分享圖片client

2.使用time模塊,在每次send的時候加入一個time.sleep(0.01),這種方法可以有效地隔開兩次send,斷開系統的優化,此種方法雖然可以解決黏包問題,但是會造成發送數據時間長

技術分享圖片server 技術分享圖片client

3,先讀取文件的大小,然後將文件的大小發送給接收端,這樣接收端就可以以文件大小來寫入數據。

技術分享圖片server 技術分享圖片client

為什麽會出現黏包問題?

首先只有在TCP協議中才會出現黏包現象

是因為TCP協議是面向流的協議

在發送的數據傳輸的過程中海油緩存機制來避免數據丟失

因為在連續發送小數據的時候、以及接收大小不符的時候都容易出現黏包現象

本質還是因為我們在接收數據的時候不知道發送的數據的長短

解決黏包問題

在傳輸大量數據之前先告訴數據量的大小。

4,使用struct解決黏包

技術分享圖片服務端(自定制報頭) 技術分享圖片客戶端(自定制報頭)

黏包問題的成因與解決方案