日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > 單片機 > CPP開發(fā)者
[導讀]事情從一個健身教練說起吧。李東,自稱亞健康終結者,嘗試使用互聯網的模式拓展自己的業(yè)務。在某款新開發(fā)的聊天軟件琛琛上發(fā)布廣告。鍵盤說來就來。瘋狂發(fā)送"李東",回車發(fā)送!,"亞健康終結者",再回車發(fā)送!還記得四層網絡協議長什么樣子嗎?四層網絡協議四層網絡模型每層各司其職,消息在進入每...


事情從一個健身教練說起吧。

李東,自稱亞健康終結者,嘗試使用互聯網 的模式拓展自己的業(yè)務。在某款新開發(fā)的聊天軟件琛琛上發(fā)布廣告。

鍵盤說來就來。瘋狂發(fā)送"李東",回車發(fā)送!,"亞健康終結者",再回車發(fā)送!

還記得四層網絡協議長什么樣子嗎?

四層網絡協議四層網絡模型每層各司其職,消息在進入每一層時都會多加一個報頭,每多一個報頭可以理解為數據報多戴一頂帽子。這個報頭上面記錄著消息從哪來,到哪去,以及消息多長等信息。比如,

mac頭部記錄的是硬件的唯一地址,

IP頭記錄的是從哪來和到哪去,傳輸層頭記錄到是到達目的主機后具體去哪個進程。

在從消息發(fā)到網絡的時候給消息帶上報頭,消息和紛繁復雜的網絡中通過這些信息在路由器間流轉,最后到達目的機器上,接受者再通過這些報頭,一步一步還原出發(fā)送者最原始要發(fā)送的消息。

四層網絡協議 (1)

為什么要將數據切片

軟件琛琛是屬于應用層上的。

而"李東","亞健康終結者"這兩條消息在進入傳輸層時使用的是傳輸層上的 TCP 協議。消息在進入傳輸層(TCP)時會被切片為一個個數據包。這個數據包的長度是

MSS。

可以把網絡比喻為一個水管,是有一定的粗細的,這個粗細由網絡接口層(數據鏈路層)提供給網絡層,一般認為是的

MTU(1500),直接傳入整個消息,會超過水管的最大承受范圍,那么,就需要進行切片,成為一個個數據包,這樣消息才能正常通過“水管”。

數據分片

MTU 和 MSS 有什么區(qū)別

MSS和MTU的區(qū)別
  • MTU: Maximum Transmit Unit,最大傳輸單元。?由網絡接口層(數據鏈路層)提供給網絡層最大一次傳輸數據的大??;一般 MTU=1500 Byte。
    假設IP層有 1500 byte 數據需要發(fā)送,需要分片才能完成發(fā)送,分片后的 IP Header ID 相同。

  • MSS:Maximum Segment Size。TCP 提交給 IP 層最大分段大小,不包含 TCP Header 和 ?TCP Option,只包含 TCP Payload ,MSS 是 TCP 用來限制應用層最大的發(fā)送字節(jié)數。
    假設 MTU= 1500 byte,那么MSS = 1500- 20(IP Header) -20 (TCP Header) = 1460 byte,如果應用層有2000 byte發(fā)送,那么需要兩個切片才可以完成發(fā)送,第一個 TCP 切片 = 1460,第二個 TCP 切片 = 540。

什么是粘包

那么當李東在手機上鍵入"李東""亞健康終結者"的時候,在 TCP 中把消息分成 MSS 大小后,消息順著網線順利發(fā)出。

發(fā)送消息到網絡網絡穩(wěn)得很,將消息分片傳到了對端手機 B 上。經過 TCP 層消息重組。變成"李東亞健康終結者"這樣的字節(jié)流(stream)。

消息從網絡接收但由于聊天軟件琛琛是新開發(fā)的,而且開發(fā)者叫小白,完了,是個臭名昭著的造 bug 工程師。經過他的代碼,在處理字節(jié)流的時候消息從"李東","亞健康終結者"變成了"李東亞","健康終結者"。"李東"作為上一個包的內容與下一個包里的"亞"粘在了一起被錯誤地當成了一個數據包解析了出來。這就是所謂的粘包。

消息對比一個號稱健康終結者的健身教練,大概運氣也不會很差吧,就祝他客源滾滾吧。

為什么會出現粘包

那就要從 TCP 是啥說起。

TCP,Transmission Control Protocol。傳輸控制協議,是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協議。

TCP是什么其中跟粘包關系最大的就是基于字節(jié)流這個特點。

字節(jié)流可以理解為一個雙向的通道里流淌的數據,這個數據其實就是我們常說的二進制數據,簡單來說就是一大堆 01 串。這些 01 串之間沒有任何邊界。

二進制字節(jié)流應用層傳到 TCP 協議的數據,不是以消息報為單位向目的主機發(fā)送,而是以字節(jié)流的方式發(fā)送到下游,這些數據可能被切割和組裝成各種數據包,接收端收到這些數據包后沒有正確還原原來的消息,因此出現粘包現象。

為什么要組裝發(fā)送的數據

上面提到 TCP切割數據包是為了能順利通過網絡這根水管。相反,還有一個組裝的情況。如果前后兩次 TCP 發(fā)的數據都遠小于 MSS,比如就幾個字節(jié),每次都單獨發(fā)送這幾個字節(jié),就比較浪費網絡 io 。

正常發(fā)送數據包比如小白爸讓小白出門給買一瓶醬油,小白出去買醬油回來了。小白媽又讓小白出門買一瓶醋回來。小白前后結結實實跑了兩趟,影響了打游戲的時間。

優(yōu)化的方法也比較簡單。當小白爸讓小白去買醬油的時候,小白先等待,繼續(xù)打會游戲,這時候如果小白媽讓小白買瓶醋回來,小白可以一次性帶著兩個需求出門,再把東西帶回來。

上面說的其實就是

TCP的Nagle 算法優(yōu)化,目的是為了避免發(fā)送小的數據包。

在 Nagle 算法開啟的狀態(tài)下,數據包在以下兩個情況會被發(fā)送:

  • 如果包長度達到

    MSS(或含有

    Fin包),立刻發(fā)送,否則等待下一個包到來;如果下一包到來后兩個包的總長度超過

    MSS的話,就會進行拆分發(fā)送;

  • 等待超時(一般為

    200ms),第一個包沒到

    MSS長度,但是又遲遲等不到第二個包的到來,則立即發(fā)送。

Nagle2
  • 由于啟動了Nagle算法,msg1 小于 mss ,此時等待

    200ms內來了一個 msg2,msg1 msg2 > MSS,因此把 msg2 分為 msg2(1) 和 msg2(2),msg1 msg2(1) 包的大小為

    MSS。此時發(fā)送出去。

  • 剩余的 msg2(2) 也等到了 msg3,同樣 msg2(2) msg3 > MSS,因此把 msg3分為msg3(1) 和 msg3(2),msg2(2) msg3(1) 作為一個包發(fā)送。

  • 剩余的 msg3(2) 長度不足

    mss,同時在

    200ms內沒有等到下一個包,等待超時,直接發(fā)送。

  • 此時三個包雖然在圖里顏色不同,但是實際場景中,他們都是一整個 01 串,如果處理開發(fā)者把第一個收到的 msg1 msg2(1) 就當做是一個完整消息進行處理,就會看上去就像是兩個包粘在一起,就會導致粘包問題。

關掉Nagle算法就不會粘包了嗎?

Nagle算法其實是個有些年代的東西了,誕生于 1984 年。對于應用程序一次發(fā)送一字節(jié)數據的場景,如果沒有 Nagle 的優(yōu)化,這樣的包立馬就發(fā)出去了,會導致網絡由于太多的包而過載。

但是今天網絡環(huán)境比以前好太多,Nagle 的優(yōu)化幫助就沒那么大了。而且它的延遲發(fā)送,有時候還可能導致調用延時變大,比如打游戲的時候,你操作如此絲滑,但卻因為 Nagle 算法延遲發(fā)送導致慢了一拍,就問你難受不難受。

所以現在一般也會把它關掉。

看起來,Nagle 算法的優(yōu)化作用貌似不大,還會導致粘包"問題"。那么是不是關掉這個算法就可以解決掉這個粘包"問題"呢?

TCP_NODELAY?=?1
關閉Nagle就不會粘包了嗎

  • 接受端應用層在收到msg1時立馬就取走了,那此時msg1沒粘包問題

  • **msg2 **到了后,應用層在忙,沒來得及取走,就呆在TCP Recv Buffer中了

  • **msg3 **此時也到了,跟msg2和msg3一起放在了TCP Recv Buffer中

  • 這時候應用層忙完了,來取數據,圖里是兩個顏色作區(qū)分,但實際場景中都是 01 串,此時一起取走,發(fā)現還是粘包。

因此,就算關閉 Nagle 算法,接收數據端的應用層沒有及時讀取 TCP Recv Buffer 中的數據,還是會發(fā)生粘包。

怎么處理粘包

粘包出現的根本原因是不確定消息的邊界。接收端在面對"無邊無際"的二進制流的時候,根本不知道收了多少 01 才算一個消息。一不小心拿多了就說是粘包。其實粘包根本不是 TCP 的問題,是使用者對于 TCP 的理解有誤導致的一個問題。

只要在發(fā)送端每次發(fā)送消息的時候給消息帶上識別消息邊界的信息,接收端就可以根據這些信息識別出消息的邊界,從而區(qū)分出每個消息。

常見的方法有

  • 加入特殊標志

    消息邊界頭尾標志可以通過特殊的標志作為頭尾,比如當收到了

    0xfffffe或者回車符,則認為收到了新消息的頭,此時繼續(xù)取數據,直到收到下一個頭標志

    0xfffffe或者尾部標記,才認為是一個完整消息。類似的像 HTTP 協議里當使用chunked 編碼傳輸時,使用若干個 chunk 組成消息,最后由一個標明長度為 0 的 chunk 結束。

  • 加入消息長度信息

消息邊界長度標志這個一般配合上面的特殊標志一起使用,在收到頭標志時,里面還可以帶上消息長度,以此表明在這之后多少 byte 都是屬于這個消息的。如果在這之后正好有符合長度的 byte,則取走,作為一個完整消息給應用層使用。在實際場景中,HTTP 中的

Content-Length就起了類似的作用,當接收端收到的消息長度小于 Content-Length 時,說明還有些消息沒收到。那接收端會一直等,直到拿夠了消息或超時。

可能這時候會有朋友會問,采用

0xfffffe標志位,用來標志一個數據包的開頭,你就不怕你發(fā)的某個數據里正好有這個內容嗎?

是的,怕,所以一般除了這個標志位,發(fā)送端在發(fā)送時還會加入各種校驗字段(

校驗和或者對整段完整數據進行

CRC之后獲得的數據)放在標志位后面,在接收端拿到整段數據后校驗下確保它就是發(fā)送端發(fā)來的完整數據。

消息邊界頭尾加校驗標志

UDP 會粘包嗎

TCP同為傳輸層的另一個協議,UDP,User Datagram Protocol。用戶數據包協議,是面向無連接,不可靠的,基于數據報的傳輸層通信協議。

UDP是什么基于數據報是指無論應用層交給 UDP 多長的報文,UDP 都照樣發(fā)送,即一次發(fā)送一個報文。至于如果數據包太長,需要分片,那也是IP層的事情,大不了效率低一些。UDP 對應用層交下來的報文,既不合并,也不拆分,而是保留這些報文的邊界。而接收方在接收數據報的時候,也不會像面對 TCP 無窮無盡的二進制流那樣不清楚啥時候能結束。正因為基于數據報和基于字節(jié)流的差異,TCP 發(fā)送端發(fā) 10 次字節(jié)流數據,而這時候接收端可以分 100 次去取數據,每次取數據的長度可以根據處理能力作調整;但 UDP 發(fā)送端發(fā)了 10 次數據報,那接收端就要在 10 次收完,且發(fā)了多少,就取多少,確保每次都是一個完整的數據報。

我們先看下IP報頭

ip報頭注意這里面是有一個 16 位的總長度的,意味著 IP 報頭里記錄了整個 IP 包的總長度。接著我們再看下UDP 的報頭。

UDP報頭在報頭中有

16bit用于指示UDP 數據報文的長度,假設這個長度是 n ,以此作為數據邊界。因此在接收端的應用層能清晰地將不同的數據報文區(qū)分開,從報頭開始取 n 位,就是一個完整的數據報,從而避免粘包和拆包的問題。

當然,就算沒有這個位(16位 UDP 長度),因為 IP 的頭部已經包含了數據的總長度信息,此時如果 IP 包(網絡層)里放的數據使用的協議是 UDP(傳輸層),那么這個總長度其實就包含了 UDP 的頭部和 UDP 的數據。

因為 UDP 的頭部長度固定為 8 字節(jié)( 1 字節(jié)= 8 位,8 字節(jié)= 64 位,上圖中除了

數據和選項以外的部分),那么這樣就很容易的算出 UDP 的數據的長度了。因此說 UDP 的長度信息其實是冗余的。

UDP數據長度

UDP?Data?的長度?=?IP?總長度?-?IP?Header?長度?-?UDP?Header?長度
可以再來看下TCP 的報頭

tcp報頭2TCP首部里是沒有長度這個信息的,跟UDP類似,同樣可以通過下面的公式獲得當前包的TCP數據長度。

TCP Data 的長度?= IP 總長度?- IP Header 長度?- TCP Header 長度。
TCP數據長度跟 UDP 不同在于,TCP 發(fā)送端在發(fā)的時候就不保證發(fā)的是一個完整的數據報,僅僅看成一連串無結構的字節(jié)流,這串字節(jié)流在接收端收到時哪怕知道長度也沒用,因為它很可能只是某個完整消息的一部分。

為什么長度字段冗余還要加到 UDP 首部中

關于這一點,查了很多資料,

《 TCP-IP 詳解(卷2)》里說可能是因為要用于計算校驗和。也有的說是因為UDP底層使用的可以不是IP協議,畢竟 IP 頭里帶了總長度,正好可以用于計算 UDP 數據的長度,萬一 UDP 的底層不是IP層協議,而是其他網絡層協議,就不能繼續(xù)這么計算了。

但我覺得,最重要的原因是,IP 層是網絡層的,而 UDP 是傳輸層的,到了傳輸層,數據包就已經不存在IP頭信息了,那么此時的UDP數據會被放在 UDP 的 ?

Socket Buffer中。當應用層來不及取這個 UDP 數據報,那么兩個數據報在數據層面其實都是一堆 01 串。此時讀取第一個數據報的時候,會先讀取到 UDP 頭部,如果這時候 UDP 頭不含 UDP 長度信息,那么應用層應該取多少數據才算完整的一個數據報呢?

因此 UDP 頭的這個長度其實跟 TCP 為了防止粘包而在消息體里加入的邊界信息是起一樣的作用的。

為什么UDP要冗余一個長度字段面試的時候咱就把這些全說出去,顯得咱好像經過了深深的思考一樣,面試官可能會覺得咱特別愛思考,加分加分。

IP 層有粘包問題嗎

IP 層會對大包進行切片,是不是也有粘包問題?

先說結論,不會。首先前文提到了,粘包其實是由于使用者無法正確區(qū)分消息邊界導致的一個問題。

先看看 IP 層的切片分包是怎么回事。

P分包與重組
  • 如果消息過長,

    IP層會按MTU 長度把消息分成N 個切片,每個切片帶有自身在包里的位置(offset)和同樣的IP頭信息。

  • 各個切片在網絡中進行傳輸。每個數據包切片可以在不同的路由中流轉,然后在最后的終點匯合后再組裝。

  • 在接收端收到第一個切片包時會申請一塊新內存,創(chuàng)建IP包的數據結構,等待其他切片分包數據到位。

  • 等消息全部到位后就把整個消息包給到上層(傳輸層)進行處理。

可以看出整個過程,

IP 層從按長度切片到把切片組裝成一個數據包的過程中,都只管運輸,都不需要在意消息的邊界和內容,都不在意消息內容了,那就不會有粘包一說了。

IP 層表示:我只管把發(fā)送端給我的數據傳到接收端就完了,我也不了解里頭放了啥東西。

聽起來就像 “我不管產品的需求傻不傻X,我實現了就行,我不問,也懶得爭了”,這思路值得每一位優(yōu)秀的劃水程序員學習,respect。

總結

粘包這個問題的根因是由于開發(fā)人員沒有正確理解 TCP 面向字節(jié)流的數據傳輸方式,本身并不是 TCP 的問題,是開發(fā)者的問題。

  • TCP 不管發(fā)送端要發(fā)什么,都基于字節(jié)流把數據發(fā)到接收端。這個字節(jié)流里可能包含上一次想要發(fā)的數據的部分信息。接收端根據需要在消息里加上識別消息邊界的信息。不加就可能出現粘包問題。

  • TCP 粘包跟Nagle算法有關系,但關閉 Nagle 算法并不解決粘包問題。

  • UDP 是基于數據報的傳輸協議,不會有粘包問題。

  • IP 層也切片,但是因為不關心消息里有啥,因此有不會有粘包問題。

  • TCP發(fā)送端可以發(fā)

    10 次字節(jié)流數據,接收端可以分

    100 次去??;

    UDP發(fā)送端發(fā)了

    10 次數據報,那接收端就要在

    10 次收完。

數據包也只是按著 TCP 的方式進行組裝和拆分,如果數據包有錯,那數據包也只是犯了每個數據包都會犯的錯而已。

最后,李東工作沒了,而小白表示

- EOF -

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內容真實性等。需要轉載請聯系該專欄作者,如若文章內容侵犯您的權益,請及時聯系本站刪除。
換一批
延伸閱讀

LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: 驅動電源

在工業(yè)自動化蓬勃發(fā)展的當下,工業(yè)電機作為核心動力設備,其驅動電源的性能直接關系到整個系統的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護是驅動電源設計中至關重要的兩個環(huán)節(jié),集成化方案的設計成為提升電機驅動性能的關鍵。

關鍵字: 工業(yè)電機 驅動電源

LED 驅動電源作為 LED 照明系統的 “心臟”,其穩(wěn)定性直接決定了整個照明設備的使用壽命。然而,在實際應用中,LED 驅動電源易損壞的問題卻十分常見,不僅增加了維護成本,還影響了用戶體驗。要解決這一問題,需從設計、生...

關鍵字: 驅動電源 照明系統 散熱

根據LED驅動電源的公式,電感內電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關鍵字: LED 設計 驅動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產業(yè)的重要發(fā)展方向。電動汽車的核心技術之一是電機驅動控制系統,而絕緣柵雙極型晶體管(IGBT)作為電機驅動系統中的關鍵元件,其性能直接影響到電動汽車的動力性能和...

關鍵字: 電動汽車 新能源 驅動電源

在現代城市建設中,街道及停車場照明作為基礎設施的重要組成部分,其質量和效率直接關系到城市的公共安全、居民生活質量和能源利用效率。隨著科技的進步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統光源,成為大功率區(qū)域...

關鍵字: 發(fā)光二極管 驅動電源 LED

LED通用照明設計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數校正(PFC)、空間受限和可靠性等。

關鍵字: LED 驅動電源 功率因數校正

在LED照明技術日益普及的今天,LED驅動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設備造成不利影響,甚至引發(fā)系統故障。因此,采取有效的硬件措施來解決L...

關鍵字: LED照明技術 電磁干擾 驅動電源

開關電源具有效率高的特性,而且開關電源的變壓器體積比串聯穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機重量也有所下降,所以,現在的LED驅動電源

關鍵字: LED 驅動電源 開關電源

LED驅動電源是把電源供應轉換為特定的電壓電流以驅動LED發(fā)光的電壓轉換器,通常情況下:LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: LED 隧道燈 驅動電源
關閉