1. 程式人生 > >socket編程 粘包和半包 問題的及處理

socket編程 粘包和半包 問題的及處理

當前 多少 分包 轉義 保存 長連接 完整 過去 高效

一般在socket處理大數據量傳輸的時候會產生粘包和半包問題,有的時候tcp為了提高效率會緩沖N個包後再一起發出去,這個與緩存和網絡有關系。

粘包 為x.5個包

半包 為0.5個包

由於網絡原因 一次可能會來 0.5/1 /2/ 2.5/ 。。。。個包

當接收到時 要先看看那這個包中有多少個完整的包。把完整的包都處理了 也就是說把x都處理了。剩下的0.5留在接收區中,等待下次接收。

這回接收到的就是0.5+1.5/0.5+1.3/0.5+0.5..... 把完整的包都處理了,有殘缺的扔掉 0.8的。

一般情況 接收到正確的後都要給發送端一個應答。不給應答的算超時,發送端將重發。

有頭沒尾的不能扔

沒頭有尾的可以扔

有頭有尾但缺東西可以扔

有頭有尾不缺東西不能扔

之所以出現粘包和半包現象,是因為TCP當中,只有流的概念,沒有包的概念.

可以使用UDP協議.這樣可以就可以區分每個包了.但是要確保包的丟失處理.為了提到效率,可以考慮寫一個滑動窗口進行收發包.

若采用TCP協議進行傳輸,就要將每個包區分開來.可以有三種方式.因為TCP是面向流的.流只有打開和關閉,你要用一個流傳輸多個包,那就要向辦法區分出每個包.

一:: 可以每次發送同樣大小的包,過大的包不予發送,過小的包,後面部分用固定的字符‘\0‘進行填充.

二:: 將流按字符處理,抽出一個字符做轉義字符(通常Java用‘\‘來做轉義字符,比如"\n"表示換行).假如就設‘\‘為轉義字符,發送方如果流當中出現‘\‘,就在後面在追加一個‘\‘,如果包結束,則用‘\‘做包的結束符.這樣,在接收方,若讀取一個單獨的‘\‘或者流結束,就標示前面的內容構成一個包,如果連續讀取兩個‘\‘,就將兩個‘\‘用一個‘\‘進行替換.這樣,就可以保證原來包中的信息不變,同時也能區分出每個包了.

三:: 在發送方發送一個包的時候,先將這個包的長度發送給對方(一般是4個字節表示包長),然後再將包的內容發送過去.接收方先接收4個字節,看看包的長度,然後按照長度來接收包,這樣就不會出錯了. 以上三種方法,是網絡傳輸中經常用到的方法.後兩種很常見.最後一種,在TCP長連接傳輸中應用最多. 綜合以上的說法,就是要在TCP協議以上再封裝一層協議,用來做分包的信息交換.

一般處理是: 一個BUFFER,用於保存當前連接的讀緩存

有數據時,Buffer = Buffer + DataIn,不停的接收

收完成後,開始解析Buffer,

根據包的協議,不停的解析Buffer,並形成一個個包進行處理,處理後,Buffer = Buffer - Data,並繼續解包

完成。

socket編程 粘包和半包 問題的及處理