C#網絡編程TCP通信的粘包問題討論

 第一個需要討論的大概就是粘包問題了。因爲這個是TCP的個性問題,UDP通信時不存在這個問題的。首先看一下什麼叫粘包:

  客戶端採取與服務器的長連接方式建立通信(Open-Write/Read-Write/Read-……-Write/Read-Close)。即建立連接之後進行多次讀寫操作,最後才關閉。而且不是文件傳輸,而是數據結構的傳輸(文件傳輸發生粘包與沒發生粘包都不會影響結果,反正都是字節流的按順序寫入本地文件)。舉個例子來說明一下吧: 兩種數據結構:{give me something} {don't give me anything}則粘包是則是接受到{give me something don't give me anything} 這個算是讓服務器傻眼了,沒見過這麼詭異的數據結構,不知道怎麼處理了。 上面的例子是轉的網上的

  來分析一下之所以發生粘包的原因吧,其實也就是爲什麼TCP會發生,但是UDP卻不會發生的原因:TCP是面向連接流式無邊界的傳輸方式。當傳輸通道建立之後,則數據流就像水一樣流過來,其中沒有數據邊界的概念,包隨便多大,因而會出現多個包最後粘成一個大包。當然這個是TCP的原因,還有就是緩衝區機制的問題,發送端在默認狀況下是需要等到發送去滿才發送出去,故而適當使用push刷緩衝區也可減少粘包的現象,還有就是接受緩衝區處理不及時,沒有做到來一個包立馬處理完這個包。

  所以解決的思路大約如下: 對於發送方引起的粘包現象,用戶可通過編程設置來避免,TCP提供了強制數據立即傳送的操作指令push,TCP軟件收到該操作指令後,就立即將本段數據發送出去,而不必等待發送緩衝區滿。此種方法關閉了優化算法,降低了網絡發送效率,影響應用程序的性能。而且並不能保證100%不發生粘包現象。

  對於接收方引起的粘包,則可通過優化程序設計、精簡接收進程工作量、提高接收進程優先級等措施,使其及時接收數據,從而儘量避免出現粘包現象。該種思路對於接收方的程序算法結構要求較高,而且可靠性不高,因爲網絡通信中的併發等現象大量存在,很難真的能完全即使處理接受緩衝區而不發生粘包。

  由接收方控制,將一包數據按結構字段,人爲控制分多次接收,然後合併,通過這種手段來避免粘包。該思路的問題就更大了,應用程序效率被降低太多。而且我實在不認爲這個真能不發生粘包,雖然包變小了,但是併發情況的存在並不能保證接收方有足夠的間隙去處理包。

  預定義數據結構,單線程。字節流前面先加上包頭標誌位,包頭中包含該包的數據長度,這樣在讀取的時候可按字節讀取。這樣可有效控制粘包問題。並可以成功避免殘包的問題,且不會發生連鎖反應,一個壞包的出現不會影響下一個包的正常讀取。如{##Length##DataStram}。該中解決方案的優點是可以保證通信的100%準確,缺點是影響程序性能,因爲按字節讀取包,必定會影響程序的效率。

  改進:預定義數據結構,單線程。但是不是按字節。查看頭標誌位,讀取包長度,查看緩衝區內包長度,兩者相等,則直接讀取。如果緩衝區內可讀字節數大於標誌位描述的包長度,則按照標誌位描述的包長度讀取數據,如果緩衝區內刻度字節數小於標誌位描述的包長度,則線程睡眠,等下一個數據包的到來。

  預定義數據結構,多線程。服務器端與客戶端都是多線程工作,客戶端爲三個主要線程:發送線程、讀取線程與解析線程。服務器端爲四個主要線程:監聽主線程、接收、讀取、解析。按照第五種的思路,拿到數據包之後直接扔給解析線程,解析線程負責數據解析以及最終結果的回調。此處比第五種多的思路就是一個多線程,從而可以很大幅度提升程序的性能。

  標誌位 長度 數據 預定義數據結構示意圖:

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