TCP新手誤區 粘包的處理

2021-10-01 22:55:38 字數 1976 閱讀 3879

最近面試了很多的學生,發現很多tcp的新手對於tcp的使用有一些誤區,而這些坑也是當初我曾經疑惑過得地方。網上很少有文章對這些問題有過詳細的解析,即是有也只是直接給出結論和做法,沒有人將其中的來龍去脈講解清楚,所以我將這些問題的來龍去脈在這一系列的文章中講述出來,希望能讓廣大tcp的新手避開這些坑。

我面試時經常會問的乙個問題是當tcp兩端a、b建立了連線後,a端先傳送100個位元組,再傳送100個位元組。那麼b端會分別收到兩次100位元組嗎?

答案是不一定會,但是只有少數人能夠正確的回答這個問題。如果能回答上這個問題那麼我會接著問那麼對於這種情況應該怎樣處理才能正確的按照傳送端傳送的長度收到資料。能完美回答出這個問題的人就更少了。

我們常說tcp是一種流式連線,這個流字到底怎麼理解?它是指tcp的資料傳輸就像一種水流一樣,並不區分不同資料報之間的界限。

就像我們開啟水龍頭後,水流自然的流出,我們並不知道背後水幫浦是分了幾次將水供上來的。

其實仔細看過tcp協議內容的人就可以發現,tcp協議允許傳送端將幾次傳送的資料報快取起來合成乙個資料報傳送到網路上去,因為這樣可以獲得更高的效率,這一行為通常是在作業系統提供的socket中實現,所以在應用層對此毫無所覺。

所以我們在程式中呼叫socketsend傳送了資料後作業系統有可能快取了起來,等待後續的資料一起傳送,而不是立即傳送出去。send的文件中對此也有說明。

網路傳輸的概念中有mtu的概念,也即是網路中乙個資料報最大的長度。如果要傳送超過這個長度的資料報,就需要分包傳送。當呼叫socketsend傳送超過mtu的資料報時,作業系統提供的socket實現會自動將這個資料報分割成幾個不超過mtu的資料報傳送。

當出現這些上面這些情況的時候,接收端就會發現接收到的資料和傳送的資料的次數不一致。這個就是粘包現象。

當我們傳輸如檔案這種資料時,流式的傳輸非常適合,但是當我們傳輸指令之類的資料結構時,流式模型就有乙個問題:無法知道指令的結束。所以粘包必須問題是必須解決的

最簡單的方法就是短連線,也就是需要傳送資料的時候建立tcp連線,傳送完乙個資料報後就斷開tcp連線,這樣接收端自然就知道資料結束了。

但是這樣的方法因為會多次建立tcp連線,效能低下。隨便用用還可以,只要稍微對效能有一點追求的人就不會使用這種方法。

使用長連線能夠獲得更好的效能但不可避免的會遇到如何判斷資料結構的開始與結束的問題。

而此時的處理方式根據資料結構的型別分兩種方式。

因為粘包問題的存在,接收端不能想當然的以為傳送端一次傳送了多少資料就能一次收到多少資料。如果傳送端傳送了乙個固定長度的資料結構,接收端必須每次都嚴格判斷接收到額資料的長度,當收到的資料長度不足時,需要再次接收資料,直到滿足長度,當收到的資料多於固定長度時,需要截斷資料,並將多餘的資料快取起來,視為長度不足需要再次接收處理。

所以對於處理粘包的關鍵在於提前獲取到資料報的長度,無論這個長度是提前商定好的還是寫在在資料報的開頭。

因為在每次傳送的資料的固定偏移位置寫入資料報的長度的方法是最通用的一種方法,所以對這種方法實現中的一些容易出錯誤的地方在此特別說明。

有些非法客戶端或者有bug的客戶端可能會發出錯誤的資料,導致解析出的資料長度異常的大,一定要對解析出的資料長度做檢查,事先規定乙個合適的長度,一旦超過果斷關閉socket,避免伺服器無休止的等待下去浪費資源。

處理完乙個完整的資料報後一定檢查是否還有未處理的資料,如果有的話要對這段多餘的資料再次開始解析資料長度的過程。不要忙著去繼續接受資料。

tcp中的粘包的處理應該是任何乙個網路程式設計人員都必須掌握的技能,但是很多被面試者向我表示從未聽說過粘包問題。面試者如果對粘包問題沒有任何的了解那麼就談不上所謂的精通、掌握socket程式設計。所以我寫這篇文章希望面試者能夠深入理解tcp的原理,掌握粘包問題,能夠取得更好的面試結果。

TCP新手誤區 心跳的意義

最近面試了很多的學生,發現很多tcp的新手對於tcp的使用有一些誤區,而這些坑也是當初我曾經疑惑過得地方。網上很少有文章對這些問題有過詳細的解析,即是有也只是直接給出結論和做法,沒有人將其中的來龍去脈講解清楚,所以我將這些問題的來龍去脈在這一系列的文章中講述出來,希望能讓廣大tcp的新手避開這些坑。...

處理tcp粘包問題

tcp是位元組流,無邊界,udp是訊息,是有邊界的。就是udp返回的就是乙個訊息。所以tcp會產生粘包問題。如何解決粘包問題,所以我們要在應用層維護訊息與訊息的邊界。比如說定長包,包尾加 r n ftp 包頭加包體長度,更複雜的應用層協議。readn接受確切資料的讀操作 cli include in...

TCP粘包的拆包處理

因為tcp是流式處理的,所以包沒有邊界,必須設計乙個包頭,裡面表示包的長度 一般用位元組表示 根據這個來逐個拆包。如果對於傳送 接收頻率不高的話,一般也就不做拆包處理了,因為不大可能有粘包現象。以下是粘包和拆包的分析 用qt的tcpsocket讀出的資料來拆 1 m imp m thread boo...