TCP粘包問題及應用層解決方法

2021-07-15 01:46:56 字數 1475 閱讀 7810

tcp和udp是存在於傳輸層的兩個網路傳輸協議,由於udp的訊息傳輸傳送是基於資料報的是有邊界的資料,而tcp是基於位元組流的資料傳輸方式,而流的方式就注定了它的無邊界性,比如在管道中流動的水就是無邊界的,如果把水裝入某個容器中在用管道傳輸,那它就是有邊界的,容器的大小就可以看成它的邊界。因此udp可以保證每次收到的都是乙個完整的資料報,而tcp缺無法保證,所以才有粘包問題。

tcp的粘包在傳送方與接收方都會出現,由於tcp有乙個緩衝區,傳送端往其中寫資料,為了增加傳送效率減小網路負擔,tcp會等緩衝區滿或者某個時間傳送此緩衝區的資料,此時粘包在傳送方就已經出現;同時接收方沒能及時處理資料,那麼後續到達的資料也會存放在緩衝區中,等待下一次讀取的時候緩衝區就形成了粘包;或者是一次寫入的資料小於緩衝區容量,在第二次寫入詩緩衝區滿了,資料直接傳送,剩下的部分會在下一次傳送時補發,因此會造成不完整的粘包等等。

在這裡所討論的是在應用層也就是socket傳輸在接收端的解決方式。

1. 傳送定長的資料報。就是說每個訊息的大小都是一樣的,接收方等待累計已接收資料的大小才會將其作為乙個完整的訊息處理;還有就是可以無用資訊填充的方式,如果某次寫入的資料不夠乙個定包長,可以在資料後填充無用資訊,這樣接收方不用累計資料,但是增加了接收方處理資料的難度。
2.  用特定的字串比如「\r\n」來做每條資料的分割。但是像「\r\n」這種串在正文中也會遇到,這樣會誤判為訊息邊界,因此在字串的選取上也應做適當的選擇。
在這種方式中就可以用到int recv(int sockfd,void *buff, size_t len,int flags);函式中flag選項;在此選項中有個屬性是peek屬性,這個屬性書不清除緩衝區,而是可先看緩衝區的內容,這樣就可以通過peek屬性想在緩衝區查詢定義的邊界來獲取資料,如果緩衝區裡不含定義邊界,則將緩衝區內容讀出,在此節後資料,如此知道找到邊界然後在處理資料;
3.  在每個 報頭上說明包體的長度,這樣通過報頭大小來獲取相應的資料大小;
在此主要討論解決方法3,在報頭說明包體大小的方式
在此方式中,每個包都分為兩部分,第一部分為資料部分的大小,緊接的部分是資料部分,可以用結構體實現
struct packet
這樣資料在傳送的過程中將報頭和包體全部傳送,在接收的時候先接收4位元組的包頭資料
int a;
recv(sockfd,&a,4,0);
或者recv(sockfd,buff,maxsize,0);//線將緩衝區資料全部拿出來再處理
strncpy(&a,buff,4);
這樣就可以獲取包體資料大小,然後通過報頭大小獲取包體資料來解決粘包
在傳送端的處理方式可以用程式設計設定來實現,tcp提供了強制資料立即傳送的操作指令push,tcp軟體收到該操作指令後,就立即將本段資料傳送出去,而不必等待傳送緩衝區滿;但是這種程式設計設定方法雖然可以避免傳送方引起的粘包,但它關閉了優化演算法,降低了網路傳送效率,影響應用程式的效能。

TCP粘包,拆包及解決方法

假設客戶端向服務端連續傳送了兩個資料報,用packet1和packet2來表示,那麼服務端收到的資料可以分為如下三種 第一種情況,接收端正常收到兩個資料報,即沒有發生拆包和粘包的現象 第二種情況,接收端只收到乙個資料報,由於tcp是不會出現丟包的,所以這乙個資料報中包含了傳送端傳送的兩個資料報的資訊...

TCP粘包,拆包及解決方法

粘包拆包問題是處於網路比較底層的問題,在資料鏈路層 網路層以及傳輸層都有可能發生。我們日常的網路應用開發大都在傳輸層進行,由於udp有訊息保護邊界,不會發生粘包拆包問題,因此粘包拆包問題只發生在tcp協議中。假設客戶端向服務端連續傳送了兩個資料報,用packet1和packet2來表示,那麼服務端收...

TCP粘包,拆包及解決方法

粘包拆包問題是處於網路比較底層的問題,在資料鏈路層 網路層以及傳輸層都有可能發生。我們日常的網路應用開發大都在傳輸層進行,由於udp有訊息保護邊界,不會發生粘包拆包問題,因此粘包拆包問題只發生在tcp協議中。假設客戶端向服務端連續傳送了兩個資料報,用packet1和packet2來表示,那麼服務端收...