tcp是基於位元組流傳輸的,只維護傳送出去多少,確認了多少,沒有維護訊息與訊息之間的邊界,因而可能導致粘包和拆包問題。
粘包問題分為兩種:
傳送方產生粘包
採用 tcp 協議傳輸資料的客戶端與伺服器經常是保持乙個長連線的狀態,雙方在連線不斷開的情況下,可以一直傳輸資料。(一次連線發一次資料不存在粘包)
但當傳送的資料報過於小,那麼 tcp 協議預設的會將這些較小的資料報進行合併傳送(緩衝區資料傳送堆壓);(如果過大,取的時候紛亂了,就是拆包。)
這個合併過程就是在傳送緩衝區中進行的,也就是說資料傳送出來它已經是粘包的狀態了。
接收方產生粘包
接收方採用 tcp 協議接收資料時的過程是這樣的:資料到運輸層,tcp 協議處理是將其放置接收緩衝區,然後由應用層來主動獲取);這時會出現乙個問題,應用層程式不能及時的把緩衝區中的資料拿出來,而下乙個資料又到來並有一部分放入的緩衝區末尾,等我們讀取資料時就是乙個粘包。(放資料的速度 > 應用層拿資料速度)(同理拆包也會發生)
tips:
tcp的短連線一般只會在 client/server間傳遞一次讀寫操作,然後任一方都可以直接進行關閉連線,而長連線則是不關閉,後續獨寫繼續使用。http的長連線和短連線本質上還是tcp長連線和短連線。具體的應用場景裡,應用層採用的連線方式不同。接收端接受包的收採用定長的方式接受,這樣每次拿出的資料都是確定乙個包的長度;
在包頭首都新增資料報的長度;
在包之間新增特殊符號作為分割。
(如果使用 netty 的話,就有專門的編碼器和解碼器解決拆包和粘包問題了。)
tips:
udp 沒有粘包問題,但是有丟包和亂序。不完整的包是不會有的,收到的都是完全正確的包。傳送的資料單位協議是 udp(當伺服器 close乙個連線時,若 client端接著發資料。根據tcp協議的規定,會收到乙個rst(就是首部的rst標誌位,表示這次的連線不能用了,需要重新建立連線)響應, client再往這個伺服器傳送資料時,系統會發出乙個sigpipe訊號給程序,告訴程序這個連線已經斷開了,不要再寫了)報文或使用者資料報,傳送的時候既不合併,也不拆分。
作為伺服器,短時間內主動關閉的連線比較多,就會造成伺服器上出現大量的time_wait連線要等2msl時間,嚴重消耗著伺服器的資源;(但是在windows下似乎預設為4分鐘就不再等了?)
作為客戶端,短時間內大量的短連線,會大量消耗client機器的埠,畢竟埠只有65535個,埠被耗盡了,後續就無法再發起新的連線了。
這個情況會出現的場景具體是這樣的:
在高並發短連線的tcp伺服器上,當伺服器處理完請求後立刻按照主動正常關閉連線。對於服務端,time-wait狀態過多的解決方法:這個場景下,會出現大量socket處於timewait狀態。如果客戶端的併發量持續很高,此時部分客戶端就會顯示連線不上。
比如,取乙個web頁面,1秒鐘的http短連線處理完業務,在關閉連線之後,這個業務用過的埠會停留在timewait狀態幾分鐘,而這幾分鐘,其他http請求來臨的時候是無法占用此埠的。單用這個業務計算伺服器的利用率會發現,伺服器幹正經事的時間和埠(資源)被掛著無法被使用的時間的比例是 1:幾百,伺服器資源嚴重浪費。
(ref:
TCP粘包 拆包
tcp粘包 拆包 客戶端發服務端傳送了兩個資料報a和b 粘包 服務端一次性接收到了a和b 拆包 服務端第一次接收了a和b的一部分,第二次接收到了b的剩餘部分 粘包 拆包原因 1 應用程式寫入的位元組大小 socket傳送緩衝區大小 2 tcp分段 tcp data部分的大小 mss max segm...
TCP粘包,拆包
粘包 拆包表現形式 現在假設客戶端向服務端連續傳送了兩個資料報,用packet1和packet2來表示,那麼服務端收到的資料可以分為三種,現列舉如下 第一種情況,接收端正常收到兩個資料報,即沒有發生拆包和粘包的現象,此種情況不在本文的討論範圍內。第二種情況,接收端只收到乙個資料報,由於tcp是不會出...
TCP粘包 拆包
粘包 拆包問題是網路比較底層的問題,在資料鏈路層 網路層以及傳輸層都有可能發生。我們日常的網路應用開發大都在傳輸層進行,由於udp有訊息保護邊界,不會發生粘包拆包問題,因此粘包拆包問題只發生在tcp協議中。假設客戶端向服務端連續傳送了兩個資料報,用packet1和packet2來表示,那麼服務端收到...