網路基礎:TCP(3):TCP沾包

imagine_tion發表於2020-12-09

一、TCP沾包的由來及解決方案

預設情況之下,TCP連線會啟動延遲傳送演算法(Nagle演算法),在資料傳送之前快取它們,如果短時間有多個資料傳送,會緩衝到一起作一次傳送(緩衝大小見 socket.bufferSize),這樣可以減少IO消耗的效能。

如果是傳輸檔案的話,那麼根本不用處理沾包的問題,來一個包拼一個包就好了。但是如果是多條資訊,或者是別的用途的資料那麼就要處理沾包。

可以參考流傳比較廣的一個例子,連續呼叫兩次send分別傳送兩端資料data1和data2,在接收端有以下幾種常見的情況:

  • A:先接收data1,然後接收data2。

  • B:先接收data1的部分資料,然後接收到data1餘下的部分資料以及data2的全部資料。

  • C:先接收到了data1的全部資料和data2的部分資料,然後接收到了data2的餘下資料。

  • D:一次性接收到了data1和data2的全部資料。

其中的B、C、D三種情況就是我們常見的沾包的情況,而對於處理沾包的問題,常見的解決方案:

  1. 多次傳送之前間隔一個等待時間:只需要等上一段時間進行下一次send就好,適用於互動頻率特別低的場景。缺點也是比較明顯的,對於比較頻繁的場景而言,傳輸效率實在太低,不過幾乎不用做什麼處理。

  2. 關閉Nagle演算法:關閉Nagle演算法,在Node.js中你可以通過socket.setNodelay()方法來關閉Nagle演算法,讓每一次send都不快取直接傳送。該方法比較適用於每次傳送的資料都比較大(但不是檔案那麼大),而且頻率不是特別高的場景。如果是每次傳送的資料量都比較少,並且頻率特別高的,關閉Nagle純屬自廢武功。另外,該方法不適用於網路較差的情況,因為Nagle演算法是在服務端進行包合併情況,但是如果短時間內客戶端的網路情況不好,或者應用層由於某些原因不能及時將TCP的資料recv(recv功能:不論是客戶還是伺服器應用程式都用recv函式從TCP連線的另一端接收資料),就會造成多個包在客戶端緩衝從而沾包的情況。(如果是在穩定的機房內部通訊那麼這個概率是比較小可以選擇忽略的)

  3. 進行封包/拆包:封包/拆包是目前業內常見的解決方案了。即給每個資料包在傳送之前,於其前/後放置一些有特徵的資料,然後收到資料的時候根據特徵資料分割出各個資料包。

二、為什麼UDP不沾包

  1. TCP協議是面向流的協議,UDP是面向訊息的協議。 UDP段都是一條資訊,應用程式必須以訊息為單位提取資料,不能一次提取任意位元組的資料。

  2. UDP具有保護訊息邊界,在每個UDP包中就有了訊息頭(訊息來源地址,埠等訊息),這樣對於接收端來說就容易進行區分處理了。傳輸協議把資料當作一條獨立的訊息在網上傳輸,接收端只能接收獨立的訊息。接收端一次只能接收傳送端發出的一個資料包,如果接收資料的大小小於傳送端一次傳送的資料大小,就會丟失一部分資料,即是丟失,接收端也不會分兩次去接收。

相關文章