怎麼解決TCP網路傳輸 粘包 問題?

時間 2021-05-05 11:19:23

1樓:

只是完整的問題被省略了一些, 面試官的意思就是問基於TCP的應用層, 如何實現按幀傳送接收的設計思路. 看到很多人槓TCP沒有包只有流, 我只想說這審題歪了.

要想實現基於TCP的按幀收發應用層協議, 當然必須意識到TCP本身被設計為乙個流協議, 怎麼把資料流切成一段一段的, 無非就兩種思路, 跟基於字元陣列的字串類似:

在幀頭部記錄幀長度, 說明接下來多少個位元組是屬於某一幀的.

在幀尾部追加特殊標記, 比如換行符.

實際應用中用幀頭部放置固定格式的元資料方式更常見, 它有許多好處:

可以提前申請動態記憶體, 並且尺寸不大不小剛剛好

幀頭部除了長度, 通常還有其它附加資訊, 用於標記這麼一塊位元組陣列如何解析

事實上整個網路棧也是按這種方式組織的, 比如IP頭/TCP頭/UDP頭等等, 俗稱無限套娃.

2樓:枯榮

你在外邊再套一層不就好了

像5abcde這樣,5是資料長度,abcde是你的大寶貝因為乙個整數佔的位元組數就那麼點,所以也不存在粘數字這種情況(例如554321,長度5不會和後面的54321粘住)

就很快樂

3樓:欲三更

tcp作為面向流的協議,不存在「粘包問題」,這個大家已經說清楚了,我補充一下國內開發人員說「粘包問題」的時候,到底想說什麼?

首先,什麼叫「包」?

在基於tcp開發應用的語境下,其實有兩種「包」,其一是tcp在傳輸的時候封裝的報文,分為包頭和負載,其二是應用開發者在應用層封裝的報文結構。

第二,什麼叫「粘」?這裡同樣有兩種含義。

其一是指,由於tcp是面向流的協議,不會按照應用開發者的期望保持send輸入資料的邊界,導致接收側有可能一下子收到多個應用層報文,需要應用開發者自己分開,有些人覺得這樣不合理(那你為啥不用udp),起了個名叫「粘包」。

其二是指,使用者資料被tcp發出去的時候,存在多個小尺寸資料被封裝在乙個tcp報文中發出去的可能性。這種「粘」不是接收側的效果,而是由於Nagle演算法(或者TCP_CORK)的存在,在傳送的時候,就把應用開發者多次send的資料,「粘」在乙個tcp報文裡面發出去了,於是,先被send的資料可能需要等待一段時間,才能跟後面被send的資料一起組成報文發出去。

日常生活中說「粘包」的人,指的可能是第一種情況,也可能是第二種,不繼續追問的話,很難知道他們到底在說什麼。

第三,這兩個其實都不是「問題」。

第乙個是tcp的應有之義,人家本身就是個面向流的協議,如果你要用它傳輸資料報(datagram),必然要自己實現stream2datagram的過程。這不叫解決問題,這叫實現功能。

第二個是tcp在實現的時候,為了解決大量小報文場景下包頭比負載大,導致傳輸價效比太低的問題,專門設計的。其實在99%的情況下,Nagle演算法根本就不會導致可感知的傳輸延遲,只是在某些場景下,Nagle演算法和延遲ACK機制碰到一起,才會導致可感知的延遲。

有些應用開發者病急亂投醫,看到Nagle演算法可能導致傳送等待,並且可以禁止掉,於是以訛傳訛說禁止Nagle演算法可以讓傳送更快。其實99%的情況下禁不禁止都一樣,延遲根本不是Nagle演算法導致的;就算真有問題,最優解決方案也不是遮蔽Nagle演算法。

最後,粘包是個「土話」,容易引起歧義,不建議沿用。stream2datagram就是stream2datagram,TCP_NODELAY就是TCP_NODELAY,不要說什麼「粘包」。

ps:說了半天忘了說怎麼解決「問題」。

第一種「粘包」,靠設計乙個帶包頭的應用層報文結構就能解決。包頭定長,以特定標誌開頭,裡帶著負載長度,這樣接收側只要以定長嘗試讀取包頭,再按照包頭裡的負載長度讀取負載就行了,多出來的資料都留在緩衝區裡即可。

其實ip報文和tcp報文都是這麼幹的。

第二種「粘包」,設定TCP_NODELAY就能遮蔽Nagle演算法,但你最好確定自己知道自己在幹什麼。

4樓:

一堆人咬文嚼字,解決方案其實很簡單,加個包頭就行。

簡單點的話,包頭只需要乙個佔4位元組的整數描述包體大小

稍微複雜點可以在大小的基礎上,再附上包型別,請求id,包內容crc,包頭crc,時間戳。

5樓:Hippop

我猜你想問的是Nagle演算法:

6樓:

「粘包」的包是程式邏輯層的資料報,不是tcp/ip底層的那個「包」,所以「粘包」是客觀存在的乙個現象。解決方案也很簡單,在資料報的頭部加上乙個包頭,包括識別符號和包長度,尾部加上乙個校驗資料(CRC32什麼的),接收的時候根據接收到的資料和包頭結構進行解析和切割就行。

7樓:

謝不邀,最近在自學計網,也同時在做相關的實驗性專案。

我敢說一年前就看到這個不明所以的概念了。剛才翻了其他回答才知道所謂「粘包」的定義。總結一下就是「send的傳送行為和recv的接收行為不對應」。

send出去1+1+1,recv可能收到2+1。但實際上TCP根本沒有對此進行約定。TCP只保證不亂、不丟、不錯。

例如sender傳送「abc」,receiver可能先收到b、再收到ac。收到b的時候TCP是不能向應用層交付資料的,因為這樣會亂序。如果receiver接著收到a,那麼ab可以交付;反之如果收到c,則TCP還要等待a到達才能向應用層交付。

因此無論應用層如何頻繁請求,都可能只能一次性接收「abc」。

TCP的具體實現我不是很清楚,但是從上面這個例子可以看出,只要TCP需要保證順序,就沒辦法在zero-overhead的情況下做到收發操作對應。而且TCP在設計上就是面向流的,乙份s次傳送的n位元組資料可能在t次recv完成接收。該如何分割和識別資料,完全是應用層的事情。

如果想要按照send和recv分割資料塊,那麼UDP更合適(代價是失去TCP的一系列傳輸控制)。UDP的載荷是完整攜帶在資料報裡面的。接收到的乙個UDP包可以視作來自sender的一次傳送。

或者也可以給傳送的位元組流新增額外的overhead,例如指示接下來幾個位元組是乙個「資料報」。或者乾脆用HTTP之類基於TCP又明確載荷位置的協議包裝一下。例如我最近在做的乙個小工具需要從伺服器更新少量配置資訊。

就乾脆用json套一下裝在nginx的HTTP response裡面返回給客戶端。

8樓:exiledkingcc

這個所謂「TCP黏包」問題,我老早就在知乎上看過,很多人都批判過。本來不想搭理的,但是看到居然有些人在這裡槓:「實踐中遇到過就懂了黏包的存在」。這真是又好氣又好笑。

你們自己先入為主地錯誤地認為send與recv是一一對應的,從而生造出「TCP黏包」這種東西,還有理了嗎?

但凡認真看了send、recv的函式簽名,就知道有返回值啊!你不該想一想send呼叫節,如果返回值比100小的時候該怎麼辦嗎?不該想一想recv快取區有節,如果返回值比100小怎麼辦嗎?

但凡動動腦子,想一下這兩個問題,也不會想到什麼「黏包」吧!

有人可能覺得,不管叫黏包問題也好,叫基於TCP設計以包為單位的應用層協議也好,叫什麼不重要,重要的是怎麼解決這個問題。

我是反對的。

基於錯誤的理解形成的概念,對於有效的交流溝通是有害的,會導致無法理清問題的實質與邊界、難以提出正確且合適的解決方案。

9樓:gyd

看到這麼多人吐槽「TCP沒有粘包」,我有點驚呆了

不知道這些大佬們用沒用過tcpdump,wireshark一類的工具,用過的都知道有個詞叫「抓包」,按一些人的說法,這個不是「包」,是「幀」,難道要說成是「抓幀」?

強調TCP沒有包真的能凸顯出個人的牛B所在嗎,我看不見得。

題主說的是「TCP網路傳輸」,網路傳輸過程中,會經過不同的協議層,附一張計算機網路中的圖。

不同的協議層有不同的資料單元稱呼,如:

鏈路層--幀

網路層--IP資料報(簡稱資料報)、分組或包

「包」的概念出現在網路層。附圖,同樣來自計算機網路第七版。

TCP網路傳輸中有幀,有包,我覺得沒毛病。

言歸正傳,

在send的時候,有時候send了兩次,網絡卡上抓包會看到只有乙個,這種情況可以參考羅宸的回答,設定nodelay後,系統會分別傳送,不會「粘包」;

在recv的時候,有時候會一次收到多個包的資料,這種情況很多回答裡都提到了,要在傳輸的資料中自定義資料邊界。

10樓:

其實壓根不存在什麼「粘包」。所謂的粘包問題,其實是不懂資料分組引起的。我們記錄乙個人的名字很簡單,乙個字串就行了。

記錄多個人的姓名怎麼辦呢,當然用字串陣列咯。所謂粘包,其實就是相當於把乙個班級的學生姓名硬塞進乙個字串裡面,導致老師看不懂這一長串名字沒法點到。這可不是粘上了分不開麼,別說,這還真挺形象的。

可是,這個問題只要每個姓名之間加個分隔符號就行了呀。。。

11樓:xchg

首先確定乙個概念:TCP傳輸的是位元組流,IP層傳輸的是資料報。

流是無邊無界。對於流來說,假設最壞的情況,那也是乙個乙個位元組到達,所以位於應用層的開發者,需要設計乙個應用層協議以確定流的邊界,才能把資料不多不少地讀完整。

所謂的丟包和粘包只是在應用層觀察到的現象,而原因就是IP層對傳輸的包的大小是有限制的,這個限制和mtu有關係,IP層會對資料進行分包。

12樓:nosn

tcp是流式協議所謂的粘包不過是應用層協議不能正確提取在使用tcp開發時要記住你可能會收到0.5個協議 1.5個協議或者2.

5個協議依次類推在面對這樣的資料流時你要能正確的從位元組流中讀取的乙個乙個的協議另外協議不可能一樣大小這就有一定的開發難度

13樓:棧廬

看到這個問題讓我想起之前做過的乙個關於粘包問題的測試,分享一下我的經驗。

發生粘包問題首先要分析粘包的原因,然後對症下藥

發生粘連現象的原因很多,可能是由傳送者或接收者引起的。

由傳送方引起的粘性資料報由TCP協議本身引起。為了提高傳輸效率,傳送方經常在傳送資料報之前收集足夠的資料。如果連續幾次傳送的資料很小,通常TCP會將資料合成為乙個資料報,然後根據優化演算法將其傳送出去,以便接收方接收粘性資料報。

接收方造成的粘性資料報是由於接收方使用者程序未及時接收資料而導致的,從而導致產生了粘性資料報。這是因為接收器首先將接收到的資料放入系統接收緩衝區中,而使用者程序則從緩衝區中獲取資料。如果下乙個資料報到達,

圖1圖2

圖3有兩種情況。一種是被粘在一起的包是完整的資料報(如圖1和圖2所示),另一種是被粘在一起的包具有不完整的包(如圖3所示),這裡假設使用者收到了乙個完整的資料報。緩衝區長度為m個位元組。

並非所有粘性資料報都需要處理。如果傳輸的資料是沒有結構的連續流資料(例如檔案傳輸),則無需分離粘合的資料報(稱為分包)。但是,在實際工程應用中,傳輸的資料一般為結構化資料,因此需要進行報文處理。

在處理定長結構資料的粘性問題時,分組打包演算法相對簡單。在處理不定長結構資料的粘性分組問題時,分組打包演算法更加複雜。特別地,如圖1所示的粘盒中所示,如圖3所示,由於資料內容的分組被分成兩個連續的接收分組,因此難以處理。

在實際工程應用中,應盡可能避免粘連。

為了避免粘附現象,可以採取以下措施。

首先,對於由傳送方引起的粘滯現象,使用者可以通過程式設計避免它。TCP提供了乙個操作指令推送,用於強制立即傳送資料。收到操作指令後,TCP軟體立即將資料傳送到該段。無需等待傳送緩衝區已滿;

其次,對於接收方造成的粘性資料報,可以優化程式設計,簡化接收過程的工作量,提高接收過程的優先順序,使其可以及時接收資料,從而避免出現粘性資料報;

第三個是由接收器控制的,根據結構欄位的資料報,多次接收人工控制,然後合併。

上述三項措施都有其不足之處。

儘管第一種程式設計方法可以避免由傳送方引起的粘性資料報,但它關閉了優化演算法,降低了網路傳輸效率,並影響了應用程式的效能。通常不建議這樣做。

第二種方法只能減少粘性資料報的可能性,而不能完全避免粘性資料報。當傳輸頻率很高時,或者因為網路突發可能使資料報更快地到達接收器,接收器仍然可以接收它,從而導致出現粘滯的包。

第三種方法避免了粘滯的資料報,但是應用程式效率較低,不適用於實時應用程式。

乙個更全面的策略是:接收方建立乙個預處理執行緒,對接收到的資料報進行預處理,並分離粘合的資料報。我們已經對該方法進行了實驗,並證明是有效且可行的,讓我們簡單看一下:

1.實施框架

實驗性網路通訊程式是通過TCP / IP協議的套接字api程式設計實現的。該套接字用於客戶機/伺服器模型。TCP實現框架如圖4所示。

圖42.實驗硬體環境:

伺服器:奔騰350微型計算機

客戶:奔騰166微機

網路平台:通過10兆共享集線器連線的LAN

3.實驗軟體環境:

作業系統:Windows 98

程式語言:Visual C ++ 5.0

4.主線程

程式設計使用多執行緒。伺服器端有兩個執行緒:傳送資料執行緒和傳送統計資訊顯示執行緒。

客戶端具有三個執行緒:接收資料執行緒,接收預處理粘性執行緒和接收統計顯示執行緒。其中,傳送和接收執行緒優先順序設定為thread_priority_time_critical(最高優先順序),預處理執行緒優先順序為thread_priority_above_normal(高於正常優先順序),顯示執行緒優先順序為thread_priority_normal(正常優先順序)。

實驗傳輸資料的資料結構如圖5所示:

圖55.打包演算法

對於這三種不同的粘滯現象,分包演算法採用了相應的解決方案。基本思想是首先將接收到的要處理的資料流(長度設定為m)轉換為預定的結構資料形式,並取出結構資料長度字段,即圖2中的n。5,然後根據n獲得第乙個包。

資料長度。

如果n如果n = m,則表示資料流內容只是乙個完整的結構資料,可以直接儲存在臨時緩衝區中。

如果n> m,則表示資料流內容不足以構成完整的結構資料,需要在處理之前將其與下乙個分組資料合併。

實驗結果如下:

1.在上述實驗環境中,當傳送方傳送的多個報文的長度之和小於1500b時,經常會發生粘連現象,接收方在經過預處理執行緒處理後可以正確解包。如果在程式中設定了「不傳送延遲」:

(setsockopt(socket_name,ipproto_tcp,tcp_nodelay,(char *)及on,sizeof on),其中on = 1),則沒有粘滯現象。

2.當傳輸資料是每個資料報1 kb到2 kb的不確定長度資料時,如果傳輸間隔小於10 ms,則偶爾會出現粘性資料報,並且接收方可以在對資料報進行預處理之後正確解壓縮這些資料報。處理執行緒。

3.為了測量處理粘性資料報的時間,傳送方順序迴圈傳送長度為1.5 kb,1.

9 kb,1.2 kb,1.6 kb和1.

0 kb的資料,總共1000個資料報。為了產生粘滯現象,接收執行緒在每次接收之前等待10ms,並且將接收緩衝區設定為5000b。結果,接收方接收到526個資料報,其中175個資料報的長度為5000b。

經過預處理執行緒處理後,可獲得1000個正確的資料報,粘性資料報處理的總時間少於1 ms。

實驗結果表明確實存在TCP粘連現象,但可以通過接收方的預處理來解決,處理時間非常短(實驗中1000包資料的總處理時間小於1ms),幾乎沒有影響應用程式的正常執行。

關於網路不穩定怎麼解決?

油菜花 網路不穩定,通常是由於網線問題 光纖訊號衰減嚴重 路由器質量 訊號干擾 電腦網絡卡驅動等引起的 網線問題 在使用有線網路時,網線的傳輸距離不能超過100公尺,且也不能超過無線WIFI訊號覆蓋的範圍,否則無線訊號就會不穩定。在網線選擇時最好採用無氧銅材質,水晶頭的接法中,需要按照標準的T568...

學校人太多,導致網路非常卡,怎麼解決?

妖精的左腿 首先,問問用聯通 移動 電信手機的同學,看看他們的是不是都卡,有不卡的就換不卡的運營商 其次,如果3大運營商都卡,不停的投訴,如果用的是移動的話,還有可能加基站,聯通電信是不可能的 因為窮 最後,以上兩個辦法都沒有,那就等5G吧,前提是你還在學校。 attempt 有相同困擾,但我認為目...

一根網線怎麼解決網路和IPTV共用?

單線復用提供一種方法吧,進入光貓設定 1,取消iptv繫結埠,記住iptv口的vlan2,網路撥號埠勾選上iptv口 3,vlan繫結新增指定網口,保證至少兩口新增原iptv口的vlan值 4,二級路由支援vlan劃分,並指定vlan值和網口 利國利家利天下 抓出iptv業務用的VLAN號,光貓改成...