日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

网络协议分析 | 传输层 :史上最全UDP、TCP协议详解,一篇通~

發(fā)布時間:2023/12/13 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 网络协议分析 | 传输层 :史上最全UDP、TCP协议详解,一篇通~ 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • UDP
    • 概念
    • 格式
    • UDP如何實現(xiàn)可靠傳輸
    • 基于UDP的應用層知名協(xié)議
  • TCP
    • 概念
    • 格式
    • 保證TCP可靠性的八種機制
      • 確認應答、延時應答與捎帶應答
      • 超時重傳
      • 滑動窗口
        • 滑動窗口協(xié)議
        • 后退n協(xié)議
        • 選擇重傳協(xié)議
      • 流量控制
      • 擁塞控制
        • 發(fā)送窗口、接收窗口、擁塞窗口
        • 快速重傳和快速恢復
    • 連接管理機制
      • 三次握手
        • 連接超時
      • 四次揮手
        • TIME_WAIT
      • 保活機制
    • TCP的數(shù)據(jù)類型
      • 交互/成塊數(shù)據(jù)流
      • 帶外數(shù)據(jù)
    • TCP粘包
    • 基于TCP的應用層知名協(xié)議


UDP

概念

UDP協(xié)議,即用戶數(shù)據(jù)報協(xié)議。為應用層提供 不可靠、無連接、基于數(shù)據(jù)報的服務。

  • 不可靠: 不保證數(shù)據(jù)從發(fā)送端正確地傳送到目的端,也無須為應用層數(shù)據(jù)保存副本,出現(xiàn)問題時(丟包,錯序達到等) UDP協(xié)議 只是簡單地通知應用程序發(fā)送失敗。因此,使用 UDP協(xié)議 的應用程序通常需要自己處理數(shù)據(jù)確認、超時重傳等邏輯。
  • 無連接: 不需要建立連接也可以發(fā)送數(shù)據(jù)。通信雙方每次發(fā)送數(shù)據(jù)都需要指定接收端的地址。
  • 基于數(shù)據(jù)報的服務: 每個 UDP數(shù)據(jù)報 都有一個長度,接收端必須以該長度為最小單位將其所有內(nèi)容一次性讀出,否則數(shù)據(jù)將被截斷。

格式

  • 16位源端端口/目的端口: 表示源端/對端的端口號,源端端口有時候可以不設(shè)置(不關(guān)心通信的端口),可以設(shè)置為 0 。
  • 16位數(shù)據(jù)報長度: 標志UDP首部與發(fā)送數(shù)據(jù)的長度之和,大小為 216,即 64K ,65535 。
  • 16位校驗和: 用于檢驗 接收的數(shù)據(jù)發(fā)送的數(shù)據(jù) 是否一致,不一致則丟棄 。校驗方法:二進制反碼求和,即對報文從頭開始的每個字節(jié)進行取反相加,高出16位則截斷高位,與低16位相加,得到校驗和。

面向數(shù)據(jù)報:

  • 數(shù)據(jù)報長度字段只有 16 位,報頭要占 8 個字節(jié),所以數(shù)據(jù)報的長度不能大于 64K- 8 。
    UDP 給應用層傳下來的報文添加首部后就會直接轉(zhuǎn)交給網(wǎng)絡(luò)層,所以對于較大的數(shù)據(jù),需要我們自己在應用層進行分包和包序管理。
  • UDP 在報頭中定義了數(shù)據(jù)長度,所以傳輸?shù)臅r候都是整條收發(fā)。
    所以接收時緩沖區(qū)必須要足夠大,如果緩沖區(qū)小于一條數(shù)據(jù)的大小會接收失敗,因為 UDP 不會交付 半條數(shù)據(jù)

UDP如何實現(xiàn)可靠傳輸

依靠UDP本身是無法實現(xiàn)可靠傳輸?shù)?#xff0c;因為無法保證數(shù)據(jù) 有序且到達 ,所以可以參考TCP的可靠性機制,在應用層也為其引入類似邏輯:

  • 引入序列號,保證數(shù)據(jù)有序。
  • 確認應答機制,保證對端能夠收到數(shù)據(jù)。
  • 引入超時重傳機制,保證數(shù)據(jù)不會丟失。

基于UDP的應用層知名協(xié)議

  • NFS: 網(wǎng)絡(luò)文件系統(tǒng)
  • TFTP: 簡單文件傳輸協(xié)議
  • DHCP: 動態(tài)主機配置協(xié)議
  • BOOTP: 啟動協(xié)議(用于無盤設(shè)備啟動)
  • DNS: 域名解析協(xié)議

TCP

概念

TCP協(xié)議,即傳輸控制協(xié)議。為應用層提供 可靠的、面向連接、基于流的服務。

  • 可靠: 通過超時重傳、數(shù)據(jù)確認等方式來確保數(shù)據(jù)報被正確地發(fā)送至目的端。
  • 面向連接: 雙方都必須先分配必要的內(nèi)核資源以建立全雙工的連接,才能開始數(shù)據(jù)的讀寫。
  • 基于流: 基于流的數(shù)據(jù)沒有邊界(長度)限制。

格式

  • 16位源端端口/目的端口: 表示源端/目的端的端口號,源端端口有時候可以不設(shè)置(不關(guān)心通信的端口),可以設(shè)置為0。
  • 32位序號: 序號是指發(fā)送數(shù)據(jù)的位置。每發(fā)送一次數(shù)據(jù),就累加一次該數(shù)據(jù)字節(jié)數(shù)的大小。序號不會從 0 或 1 開始,而是在建立連接時由計算機生成的隨機數(shù)作為其初始值(ISN,初始序號值),通過 SYN包 傳給接收端主機。后續(xù)報文中序號值將被設(shè)置為 ISN+報文攜帶數(shù)據(jù)的第一個字節(jié)在整個字節(jié)流中的偏移 。如:后續(xù) 某個TCP報文段 傳送的數(shù)據(jù)是字節(jié)流中的 第 1025~2048 字節(jié) ,那么該報文段的序號值為 ISN+1025 。
  • 32位確認序號: 對發(fā)送端發(fā)來的TCP報文段的響應,其值是 收到的TCP報文段的序號+1 。而發(fā)送端接收到這個確認序號以后可以認為在確認序號以前的數(shù)據(jù)都已經(jīng)被正常接收。TCP通過序號和確認序號來實現(xiàn)包序管理,確保TCP數(shù)據(jù)是有序交付的。
  • 4位數(shù)據(jù)偏移(首部長度): 標識該 TCP 頭部有多少個 32bit(4字節(jié))。因為 4位 最大能表示 15(24 -1)個,所以 TCP頭部最長是60字節(jié)。
  • 6位保留位: 保留為今后使用,一般設(shè)置為 0 。
  • 6位標志位: 有六種標志位,用來描述本報文的性質(zhì):
  • URG(Urgent Flag): 該位為 1 時,表示包中有需要緊急處理的數(shù)據(jù)。對于需要緊急處理的數(shù)據(jù),會在后面的緊急指針中再進行解釋。
  • ACK(Acknowledge Flag): 該位為 1 時,確認應答的字段變?yōu)橛行Аy帶ACK標志的稱為 確認報文段 。
  • PSH(Push Flag): 該位為 1 時,表示接收端應該立刻從 TCP接收緩沖區(qū)中讀走數(shù)據(jù),傳輸給上層的應用。為 0 時,則不需要立即讀取而是先進行緩存。
  • RST(ResetFlag): 該位為 1 時,要求接收方重新建立連接。攜帶RST標志的稱為 復位報文段 。下面討論產(chǎn)生 復位報文段 的三種情況:
    • 當客戶端訪問一個不存在的端口時,服務器就可以返回一個RST設(shè)置為 1 的包(報文中 接受通告窗口【seq】大小為 0 ,因此不能被回應),告訴客戶端關(guān)閉連接或者重新連接。
    • 可用于 異常終止 連接,不發(fā)送 結(jié)束報文段 而直接發(fā)送 復位報文段 ,發(fā)送端所有排隊等待發(fā)送的數(shù)據(jù)都將被丟棄。
    • 服務器(或客戶端)關(guān)閉或者異常終止了連接 ,而客戶端(或服務器)由于斷網(wǎng)、重啟等原因 沒有接收到發(fā)來的結(jié)束報文段 ,恢復正常后客戶端(或服務器)還 維持著原來的連接 。客戶端(或服務器)的這種狀態(tài)稱為 半打開狀態(tài),處于這種狀態(tài)的連接叫 半打開連接 。如果客戶端(或服務器)往 半打開連接 寫入數(shù)據(jù),對方會回應一個 復位報文段 。
  • SYN(Synchronize Flag): SYN為 1 表示希望建立連接,并在其序列號的字段進行序列號初始值的設(shè)定。攜帶SYN標志的稱為 同步報文段 。
  • FIN(Finish Flag): 該位為 1 時,表示通知對方本端今后不會再有數(shù)據(jù)發(fā)送,希望斷開連接。當通信結(jié)束希望斷開連接時,通信雙方的主機之間就可以相互交換FIN位置為 1 的TCP段。每個主機又對對方的FIN包進行確認應答以后就可以斷開連接。不過,主機收到FIN設(shè)置為 1 的TCP端以后不必馬上回復一個FIN包,而是可以等到緩沖區(qū)中所有數(shù)據(jù)都已成功發(fā)送而被自動刪除之后再發(fā)。攜帶FIN標志的稱為 結(jié)束報文段 。
  • 16位窗口大小: 是TCP流量控制的一個手段。這里說的窗口,指的是接收通告窗口。它告訴對方 本端的TCP接收緩沖區(qū) 還能容納多少字節(jié)的數(shù)據(jù),這樣對方就可以控制發(fā)送數(shù)據(jù)的速度。用于實現(xiàn)滑動窗口機制,來進行流量控制。
  • 16位校驗和: 由發(fā)送端填充,用于檢驗接收的數(shù)據(jù)(TCP頭部+數(shù)據(jù)部分)與發(fā)送的數(shù)據(jù)是否一致,不一致則丟棄 。校驗方法CRC算法:二進制反碼求和,即對報文從頭開始的每個字節(jié)進行取反相加,高出16位則截斷高位,與低16位相加,得到校驗和。是TCP可靠傳輸?shù)囊粋€重要保障。
  • 16位緊急指針: 是一個正的偏移量。它和序號字段的值相加表示最后一個緊急數(shù)據(jù)(帶外數(shù)據(jù))的下一個字節(jié)的序號。
  • 0-40字節(jié)選項: 選項字段用于提高TCP的傳輸性能,主要協(xié)商和描述一些信息。因為TCP首部大小最高為60字節(jié),而前面必須的有20字節(jié),所以選項的大小可以為0-40字節(jié)。
kind(1字節(jié))length(1字節(jié))info(n字節(jié))

kind 說明選項類型;length (如果有的話)指定該選項長度 ;info (如果有的話)指選項的具體信息。

  • kind=0是選項表結(jié)束選項。
  • kind=1是空操作(nop)選項。 沒有特殊含義,一般用于將TCP選項的總長度填充為4字節(jié)的整數(shù)倍。
  • kind=2是最大報文段長度選項。 TCP連接初始化時,通信雙方使用該選項來協(xié)商最大報文段長度(Max Segment Size,MSS)。TCP模塊通常將MSS設(shè)置為 (MTU-40)字節(jié)(減掉的這40字節(jié)包括20字節(jié)的TCP頭部和20字節(jié)的IP頭部)。這樣攜帶TCP報文段的IP數(shù)據(jù)報的長度就不會超過MTU(假設(shè)TCP頭部和IP頭部都不包含選項字段,并且這也是一般情況),從而避免本機發(fā)生IP分片。對以太網(wǎng)而言,MSS值是 1460(1500-40)字節(jié) 。
  • kind=3是窗口擴大因子選項。 TCP連接初始化時,通信雙方使用該選項來協(xié)商接收通告窗口的擴大因子。在TCP的頭部中,接收通告窗口大小是用 16位 表示的,故最大為 65535字節(jié) ,但實際上TCP模塊允許的接收通告窗口大小遠不止這個數(shù)。假設(shè)TCP頭部中的 接收通告窗口大小是N ,窗口擴大因子(移位數(shù))是M,那么TCP報文段的實際接收通告窗口大小是 N*2M ,或者說 N左移M位 。注意,M的取值范圍是0~14 。我們可以通過修改 proc/sys/net/ipv4/tcp_window_scaling 內(nèi)核變量來啟用或關(guān)閉窗口擴大因子選項。和MSS選項一樣,窗口擴大因子選項只能出現(xiàn)在同步報文段中,否則將被忽略。 但同步報文段本身不執(zhí)行窗口擴大操作,即同步報文段頭部的接收通告窗口大小就是該TCP報文段的實際接收通告窗口大小。當連接建立好之后,每個數(shù)據(jù)傳輸方向的窗口擴大因子就固定不變了。
  • kind=4是選擇性確認(Selective Acknowledgment,SACK)選項。 TCP通信時,如果某個TCP報文段丟失,則TCP模塊會重傳最后被確認的TCP報文段后續(xù)的所有報文段,這樣原先已經(jīng)正確傳輸?shù)腡CP報文段也可能重復發(fā)送,從而降低了TCP性能。SACK技術(shù)正是為改善這種情況而產(chǎn)生的,它使TCP模塊只重新發(fā)送丟失的TCP報文段,不用發(fā)送未被確認的TCP報文段之后所有報文段。我們可以通過修改/proc/sys/net/ipv4/tcp_sack內(nèi)核變量來啟用或關(guān)閉選擇性確認選項。
  • kind=5是SACK實際工作的選項。 該選項的參數(shù)告訴發(fā)送方本端已經(jīng)收到并緩存的不連續(xù)的數(shù)據(jù)塊,從而讓發(fā)送端可以據(jù)此檢查并重發(fā)丟失的數(shù)據(jù)塊。每個塊邊沿(edge of block)參數(shù)包含一個 4字節(jié) 的序號。其中 塊左邊沿 表示 不連續(xù)塊的第一個數(shù)據(jù)的序號 ,而 塊右邊沿 則表示 不連續(xù)塊的最后一個數(shù)據(jù)的序號的下一個序號 。這樣一對參數(shù)(塊左邊沿和塊右邊沿)之間的數(shù)據(jù)是沒有收到的。因為一個塊信息占用 8字節(jié) ,所以TCP頭部選項中實際上最多可以包含4個這樣的不連續(xù)數(shù)據(jù)塊(考慮選項類型和長度占用的2字節(jié))。
  • kind=8是時間戳選項。 該選項提供了較為準確的計算通信雙方之間的回路時間(Round Trip Time,RTT)的方法,從而為TCP流量控制提供重要信息。 我們可以通過修改 /proc/sys/net/ipv4/tcp_timestamps 內(nèi)核變量來啟用或關(guān)閉時間戳選項。

保證TCP可靠性的八種機制

為了保證可靠傳輸,TCP提出了8種機制:

  • 確認應答機制
  • 延時應答機制
  • 捎帶應答機制
  • 超時重傳機制
  • 滑動窗口機制
  • 流量控制機制
  • 擁塞控制機制
  • 快速重傳機制

  • 確認應答、延時應答與捎帶應答

    確認應答

    TCP中,確認應答機制(ACK報文) 是保證數(shù)據(jù)可靠傳輸?shù)暮诵臋C制:

    • TCP將每個字節(jié)的數(shù)據(jù)都進行了編號,即為序列號。
    • 每一個ACK都帶有對應的確認序列號,意思是告訴發(fā)送者,我已經(jīng)收到了哪些數(shù)據(jù);下一次你從哪里開始發(fā)(應答)。
    • 而且此時給請求和應答都對應帶上編號,既能保證數(shù)據(jù)傳輸沒有歧義,也不會浪費太多的空間和寬帶。
    • TCP規(guī)定,除了第一次握手時的SYN包之外,其他TCP報文段必須攜帶 確認報文 。

    延時應答

    基于確認應答機制,但接收端收到發(fā)送端發(fā)來的數(shù)據(jù)后并 不立即返回ACK應答

    • 立即返回ACK應答的話,這時候的接收緩沖區(qū)中的數(shù)據(jù)還沒能夠處理,緩存區(qū)的剩余大小就是窗口大小。
    • 但實際上應用程序可能很快就會讀走接收緩沖區(qū)中的內(nèi)容,因此我們 延遲一會 ,等待緩存區(qū)中數(shù)據(jù)被處理,那么剩余的緩存區(qū)就會大些。

    是不是所有的包都可以延時應答?

  • 數(shù)量限制:每隔 N(默認N=2) 個包就應答一次
  • 時間限制:超過最大延時時間就應答一次(默認為 200ms)
  • 捎帶應答

    在延時應答的基礎(chǔ)上,接受方和發(fā)送方都是 一發(fā)一收,所以,我們在發(fā)送數(shù)據(jù)的時候,將ACK以搭順風車的方式發(fā)送給對方。


    超時重傳

    實際網(wǎng)絡(luò)中會有丟包的可能,TCP模塊為每個TCP報文段都維護一個重傳定時器 ,該定時器在TCP報文段第一次發(fā)送時啟動。如果 超時時間內(nèi) 未收到接收方的 確認報文段 ,TCP模塊將 重傳丟失的TCP報文段重置定時器 。

    兩種原因?qū)е碌某瑫r重傳

    假設(shè) A 給 B 發(fā)送 TCP報文段 ,造成TCP報文段超時重傳有兩種原因:

  • A發(fā)給B的TCP報文段丟了。
  • B發(fā)給A的ACK報文段丟了。
    • 如果是第一種,那對雙方?jīng)]什么影響,重發(fā)就行。
    • 但是如果第二種情況,那么 B 就會收到 已經(jīng)確認過的TCP報文 ,那么 B 需要能夠識別出這是之前重復的包,我回應的ACK報文丟了?還是新的一次請求,需要新的ACK報文?這時候可以利用序列號,由于重發(fā)的TCP報文序列號跟之前一樣,因此 B 就知道原來是 之前回應的ACK報文丟了 ,那重發(fā)一次就好了。

    超時重傳的時間

    超時時間的設(shè)置是很有講究的:

    • 如果超時時間設(shè)的太長,會影響整體的重傳效率;
    • 如果超時時間設(shè)的太短,有可能會頻繁發(fā)送重復的包,對接收方造成困擾。

    Linux 中(BSD Unix 和 Windows 也是如此),超時以 500ms 為一個單位進行控制,每次超時時間都是 500ms 的整數(shù)倍。

    根據(jù) karn算法 :RTO(新的重傳時間)= γ × RTO(舊的重傳時間)【系數(shù) γ 的典型值是2】

    • 如果重發(fā)一次之后,仍然得不到應答,等待 2*500ms 后再進行重傳。
    • 如果仍然得不到應答,等待 4*500ms 進行重傳,依次類推。
    • 累計到一定的重傳次數(shù),TCP認為 網(wǎng)絡(luò) or 對端主機 出現(xiàn)異常,強制關(guān)閉連接。

    超時重傳的次數(shù)

    Linux 有兩個重要內(nèi)核參數(shù)管理TCP的超時重傳次數(shù):

    • /proc/sys/net/ipv4/tcp_retries1 :指定在底層 IP 和 ARP 接管之前 最少 要執(zhí)行多少次重傳。默認值是 3 。
    • /proc/sys/net/ipv4/tcp_retries2 : 指定強制關(guān)閉連接前TCP 最多 可以執(zhí)行的重傳次數(shù) ,默認值為 15 (一般對應 13~30min ,可以用 date命令 測量)。

    滑動窗口

    從前面的確認應答機制可以看到,如果對于每一個數(shù)據(jù),都需要等到回復確認,才發(fā)送下一個數(shù)據(jù),就會導致效率的低下,尤其是網(wǎng)絡(luò)較差時,數(shù)據(jù)的往返之間過長的情況。既然這樣一收一發(fā)的效率過慢,那么一次性發(fā)送多條,就可以解決這種問題,但是如果發(fā)送的數(shù)量過多,就可能會導致緩沖區(qū)溢出而丟包,為了控制發(fā)送數(shù)據(jù)的規(guī)模,于是TCP就引入了滑動窗口機制。

    在TCP首部中我們看到有一個 16位窗口大小的字段 ,那個就是滑動窗口的大小,其意味著接收方還有多大的緩沖區(qū)可以用于接收數(shù)據(jù)。發(fā)送方可以通過滑動窗口的大小來確定應該發(fā)送多少字節(jié)的數(shù)據(jù),在三次握手的時候雙方進行協(xié)商,規(guī)定好通信時的 MSS 和 窗口大小 。當滑動窗口為 0 時,發(fā)送方一般不能再發(fā)送數(shù)據(jù)報,但有兩種情況除外:

    • 可以發(fā)送 緊急數(shù)據(jù) 。
    • 發(fā)送方可以發(fā)送一個 1字節(jié) 的數(shù)據(jù)報來通知接收方重新聲明它希望接收的下一字節(jié)及發(fā)送方的滑動窗口大小。

    發(fā)送端維護發(fā)送窗口:用于限制一次能夠發(fā)送的數(shù)據(jù)。

    • 后沿:數(shù)據(jù)發(fā)送的起始位置,等待確認回復的數(shù)據(jù),如果得到了回復,則后沿移動。
    • 前沿:數(shù)據(jù)發(fā)送的結(jié)束位置,前沿減去后沿必須小于等于窗口大小,移動取決于窗口大小。

    接收端維護接受窗口:用于進行數(shù)據(jù)的排序。

    • 后沿:數(shù)據(jù)接受的起始位置,移動取決于是否收到后沿數(shù)據(jù)。
    • 前沿:接收緩沖區(qū)剩余空間大小加上后沿,移動取決于接收緩沖區(qū)剩余大小。

    下面舉例說明,假設(shè)發(fā)送窗口尺寸為2,接收窗口尺寸為1:

  • 初始態(tài),發(fā)送方?jīng)]有幀發(fā)出,發(fā)送窗口前后沿相重合。接收方0號窗口打開,等待接收0號幀;
  • 發(fā)送方打開0號窗口,表示已發(fā)出0幀但尚未確認返回信息。此時接收窗口狀態(tài)不變;
  • 發(fā)送方打開0、1號窗口,表示0、1號幀均在等待確認之列。至此,發(fā)送方打開的窗口數(shù)已達規(guī)定限度,在未收到新的確認返回幀之前,發(fā)送方將暫停發(fā)送新的數(shù)據(jù)幀。接收窗口此時狀態(tài)仍未變;
  • 接收方已收到0號幀,0號窗口關(guān)閉,1號窗口打開,表示準備接收1號幀。此時發(fā)送窗口狀態(tài)不變;
  • 發(fā)送方收到接收方發(fā)來的0號幀確認返回信息,關(guān)閉0號窗口,表示從重發(fā)表中刪除0號幀。此時接收窗口狀態(tài)仍不變;
  • 發(fā)送方繼續(xù)發(fā)送2號幀,2號窗口打開,表示2號幀也納入待確認之列。至此,發(fā)送方打開的窗口又已達規(guī)定限度,在未收到新的確認返回幀之前,發(fā)送方將暫停發(fā)送新的數(shù)據(jù)幀,此時接收窗口狀態(tài)仍不變;
  • 接收方已收到1號幀,1號窗口關(guān)閉,2號窗口打開,表示準備接收2號幀。此時發(fā)送窗口狀態(tài)不變;
  • 發(fā)送方收到接收方發(fā)來的1號幀收畢的確認信息,關(guān)閉1號窗口,表示從重發(fā)表中刪除1號幀。此時接收窗口狀態(tài)仍不變。
  • 根據(jù)窗口尺寸的大小不同,滑動窗口分為 1比特滑動窗口、后退n 及 選擇重傳 三種協(xié)議:

    • 1比特滑動窗口協(xié)議:發(fā)送窗口=1,接收窗口=1;
    • 后退n協(xié)議:發(fā)送窗口>1,接收窗口=1;
    • 選擇重傳協(xié)議:發(fā)送窗口>1,接收窗口>1。

    滑動窗口協(xié)議

    當發(fā)送窗口和接收窗口的大小固定為1時,滑動窗口協(xié)議退化為停等協(xié)議(stop-and-wait)。該協(xié)議規(guī)定發(fā)送方每發(fā)送一幀后就要停下來,得到回復后才能繼續(xù)發(fā)送下一幀。


    后退n協(xié)議

    由于停等協(xié)議要為每一個幀進行確認后才繼續(xù)發(fā)送下一幀,大大降低了信道利用率,因此又提出了后退n協(xié)議。

    后退n協(xié)議中,發(fā)送方在發(fā)完一個數(shù)據(jù)幀后,不停下來等待應答幀,而是連續(xù)發(fā)送若干個數(shù)據(jù)幀。且發(fā)送方在每發(fā)送完一個數(shù)據(jù)幀時都要設(shè)置超時定時器。如果 某幀在計時器超時后仍未返回其確認信息,就要重發(fā)該幀及后續(xù)所有幀。

    從這里不難看出,后退n協(xié)議一方面因連續(xù)發(fā)送數(shù)據(jù)幀而提高了效率,但另一方面,在重傳時又必須把原來已正確傳送過的數(shù)據(jù)幀進行重傳(僅因這些數(shù)據(jù)幀之前有一個數(shù)據(jù)幀出了錯),這種做法又使傳送效率降低。


    選擇重傳協(xié)議

    在后退n協(xié)議中,接收方若發(fā)現(xiàn)錯誤幀就不再接收后續(xù)正確到達的幀,這顯然是一種浪費,因此提出了選擇重傳協(xié)議。

    選擇重傳協(xié)議(SELECTICE REPEAT)中,接收方發(fā)現(xiàn)某幀出錯后,其后繼續(xù)送來的正確的幀 雖然不能立即遞交給接收方的高層,但接收方仍可收下來,存放在一個緩沖區(qū)中,同時要求發(fā)送方重新傳送出錯的那一幀。 一旦收到重新傳來的幀后,就可以原已存于緩沖區(qū)中的其余幀一并按正確的順序遞交高層。

    顯然,選擇重發(fā)減少了浪費,但要求接收方有足夠大的緩沖區(qū)空間。


    流量控制

    接收端處理數(shù)據(jù)的速度是有限的,如果發(fā)送端發(fā)的太快,導致接收端的緩沖區(qū)滿, 這個時候如果發(fā)送端繼續(xù)發(fā)送,就會造成丟包,繼而引起丟包重傳等等一系列連鎖反應。

    因此TCP提出了 流量控制機制:根據(jù)接收端的處理能力,來決定發(fā)送端的發(fā)送速度。

    • TCP連接階段,雙方協(xié)商窗口尺寸,同時接收方預留數(shù)據(jù)緩存區(qū);
    • 發(fā)送方根據(jù)協(xié)商的結(jié)果,發(fā)送符合窗口尺寸的數(shù)據(jù)字節(jié)流,并等待對方的確認;
    • 接收端將 接收緩沖區(qū)空閑大小 放入 TCP 首部中的 窗口大小字段,通過ACK報文通知發(fā)送端。窗口大小字段越大,說明網(wǎng)絡(luò)的吞吐量越高;
    • 發(fā)送方根據(jù)確認信息,改變窗口的尺寸,增加或者減少發(fā)送未得到確認的字節(jié)流中的字節(jié)數(shù)。
    • 如果接收端緩沖區(qū)滿了,就會將窗口置為0,這時發(fā)送方不再發(fā)送數(shù)據(jù),但是需要定期發(fā)送一個窗口探測數(shù)據(jù)段,詢問接收端當前 接收緩沖區(qū)的空閑大小
    • 如果出現(xiàn)發(fā)送擁塞,發(fā)送窗口縮小為原來的一半,同時將超時重傳的時間間隔擴大一倍。

    而在傳輸過程中,發(fā)送窗口(SWND)的大小并不僅僅取決于接收窗口(RWND),還取決于下文將提到的擁塞窗口(CWND)。


    擁塞控制

    擁塞控制的作用是:提高網(wǎng)絡(luò)利用率、降低丟包率,并保證網(wǎng)絡(luò)資源對每條數(shù)據(jù)流的公平性。

    擁塞控制有四個部分:

    • 慢啟動(slow start)
    • 擁塞避免(congestion avoidance)
    • 快速重傳(fast retransmit)
    • 快速恢復(fast recovery)

    擁塞控制算法或者部分或者全部實現(xiàn)了上述四個部分。/proc/sys/net/ipv4/tcp_congestion_control 文件指示當前所使用擁塞控制算法。

    這里介紹一個擁塞控制算法——Nagle算法

    Nagle算法:為了盡可能發(fā)送大塊數(shù)據(jù),避免網(wǎng)絡(luò)中充斥著許多小數(shù)據(jù)塊。 主要用于解決交互數(shù)據(jù)流(見下文)帶來的網(wǎng)絡(luò)擁塞。

    • 要求一個TCP連接通信雙方在任意時刻都最多只能發(fā)送一個未被確認的TCP報文段,在該TCP報文段的確認到達之前不能發(fā)送新的TCP報文段。
    • 發(fā)送方在等待ACK報文的同時收集本端下次需要發(fā)送的微量數(shù)據(jù),并在確認到來時以一個TCP報文段將它們?nèi)堪l(fā)送出去。這樣就大大減少了網(wǎng)絡(luò)上的微小TCP報文段的數(shù)量。

    Nagle更詳細的發(fā)送規(guī)則:

  • 如果包長度達到MSS,則允許發(fā)送;
  • 如果該包含有FIN,則允許發(fā)送;
  • 設(shè)置了TCP_NODELAY選項,則允許發(fā)送;
  • 未設(shè)置TCP_CORK選項時,若所有發(fā)出去的小數(shù)據(jù)包(包長度小于MSS)均被確認,則允許發(fā)送;
  • 上述條件都未滿足,但發(fā)生了超時(一般為200ms),則立即發(fā)送。

  • 發(fā)送窗口、接收窗口、擁塞窗口

    • 擁塞控制的最終受控變量是 發(fā)送端向網(wǎng)絡(luò)一次連續(xù)寫入的數(shù)據(jù)量 ,被稱為 發(fā)送窗口(SWND,Send Window)。
    • 發(fā)送窗口限定了發(fā)送端能連續(xù)發(fā)送的TCP報文段數(shù)量。這些TCP報文段 數(shù)據(jù)部分的最大長度 稱為 發(fā)送者最大段大小(SMSS)。 其值一般等于 最大報文長度(MSS)。
    • 發(fā)送端要合理選擇SWND大小,太小需要在網(wǎng)絡(luò)上頻繁的傳輸確認信息,導致通信效率下降;太大容易產(chǎn)生多次丟包重傳(從快速局域網(wǎng)進入慢速局域網(wǎng)、接收端緩存不夠溢出),導致網(wǎng)絡(luò)擁塞。
    • 接收端 可以通過 接收窗口(RWND)來控制 發(fā)送端 的 SWND。但還不夠,發(fā)送端還引入了 擁塞窗口(CWND,Congestion Window)這個狀態(tài)變量。SWND值 是 RWND 和 CWND 中的較小值。

    擁塞窗口

    • 發(fā)送開始的時候,定義擁塞窗口初始值為 IW(Initial Window) ,大小為 1個MSS ;
    • 每收到一個ACK應答,擁塞窗口: CWND*=2 。

    第二點就是上面提到的 慢啟動 :TCP模塊一開始并不清楚網(wǎng)絡(luò)的實際情況,因為需要用一種試探的方式平滑地增加CWND的大小。但慢啟動實際上并不慢,如果不加限制,慢啟動必然使得CWND指數(shù)級增長,并最終導致網(wǎng)絡(luò)擁塞。為了避免網(wǎng)絡(luò)擁塞,擁塞控制定義了 慢啟動門限(slow start threshold size,ssthresh) 這個狀態(tài)變量。當CWND大小超過該值時,TCP擁塞控制將進入 擁塞避免階段

    • cwnd < ssthresh,慢開始算法。
    • cwnd>ssthresh,擁塞避免算法。采用 加法增大 的策略,即CWND不再以 2倍 的方式增加,而是轉(zhuǎn)變?yōu)?每次加1 的方式。
    • cwnd = ssthresh,兩者皆可。

    正如上圖所示,擁塞避免并不能避免網(wǎng)絡(luò)擁塞發(fā)生,它只是 將CWND由指數(shù)增長拉低到線性增長,降低出現(xiàn)擁塞的可能。 當網(wǎng)絡(luò)擁塞發(fā)生時,CWND迅速縮小,那么 發(fā)送端是如何判斷擁塞發(fā)生的呢?

    • 傳輸超時,或者說TCP重傳定時器溢出。
    • 接收到重復的確認報文段。

    擁塞控制對這兩種情況有不同的處理方式:

    • 第一種情況:慢啟動和擁塞避免。
    • 第二種情況:快速重傳和快速恢復。如果第二種情況發(fā)生在重傳定時器溢出之后,則也被當成第一種情況來對待。

    當發(fā)送端檢測出 擁塞發(fā)生 是由于第一種情況,會執(zhí)行 擁塞避免

    • ssthresh = CWND/2 :CWND是擁塞發(fā)生時的擁塞窗口大小。
    • CWND=MSS :重置CWND的值,重新開始慢啟動。

    快速重傳和快速恢復

    快速重傳

    假設(shè)發(fā)送方發(fā)送了 M1–M4 四個分組,接收方收到了 M1、M2、M4 ,接收方不能確認 M4,因為 M3 沒有收到。 此時接收方可以什么都不干,但 快重傳算法要求接收方繼續(xù)發(fā)送對M2的確認:

    • 發(fā)送方還會試著發(fā)送 M5、M6,接收方繼續(xù)發(fā)送對 M2 的重復確認,這樣可以讓發(fā)送方知道 M3 并沒有被傳過來。按照規(guī)定,只要發(fā)送方收到三個重復確認(加上一個正常確認,總共發(fā)送了4個ACK報文),就立即重傳確認序號指向的數(shù)據(jù)(對方未收到的報文段 M3),這樣 比起等待 M3 超時后進行重傳效率快了很多,因此被叫做快速重傳。

    快速恢復

    當出現(xiàn)了快重傳的情況時,就說明當前網(wǎng)絡(luò)狀況存在問題,但是又由于我們能夠連續(xù)三次收到確認應答,就說明了當前的問題并不是很嚴重,沒有必要重新進行慢開始。所以當前會:

    • 將 ssthresh 設(shè)置為 當前CWND大小 的一半
    • 將 CWND 設(shè)置為 新的ssthresh
    • 然后實行擁塞避免算法

    由于跳過了慢開始階段直接進行擁塞避免,因此被稱為快恢復。


    連接管理機制

    這篇關(guān)于三次握手四次揮手的博客很全:面試官,不要再問我三次握手和四次揮手

    三次握手

    • 第一次握手:客戶端發(fā)送網(wǎng)絡(luò)包,服務端收到了。
      這樣 服務端 就能得出結(jié)論:客戶端的發(fā)送能力、服務端的接收能力是正常的。
    • 第二次握手:服務端發(fā)包,客戶端收到了。
      這樣 客戶端 就能得出結(jié)論:服務端的接收、發(fā)送能力,客戶端的接收、發(fā)送能力是正常的。 不過此時 服務器并不能確認客戶端的接收能力是否正常。
    • 第三次握手:客戶端發(fā)包,服務端收到了。
      這樣 服務端 就能得出結(jié)論:客戶端的接收、發(fā)送能力正常,服務器自己的發(fā)送、接收能力也正常。

    socket 接口與三次握手:

    為什么握手不能兩次?即客戶端發(fā)起SYN連接,服務端確認后回復ACK+SYN就直接建立連接。

    如果只有兩次就能建立連接,那就代表著就容易產(chǎn)生這種情況:

  • 如客戶端發(fā)出連接請求,但因連接請求報文丟失而未收到確認,于是客戶端再重傳一次連接請求。
  • 客戶端收到了第二個請求報文的確認,與服務器建立了連接。數(shù)據(jù)傳輸完畢后,就釋放了連接。
  • 然而第一個丟失的請求報文段只是在某些網(wǎng)絡(luò)結(jié)點長時間滯留了。假定這個滯留時間未超過MSL,并且延誤到連接釋放以后的某個時間才到達服務端。
  • 此時服務端誤認為客戶端又發(fā)出一次新的連接請求,于是就向客戶端發(fā)出確認報文段,同意建立連接,不采用三次握手,只要服務端發(fā)出確認,就建立新的連接了。
  • 但此時客戶端并不想和服務器建立連接,因此忽略服務端發(fā)來的確認,也不發(fā)送數(shù)據(jù),則服務端一致等待客戶端發(fā)送數(shù)據(jù),浪費資源。
  • 為什么不用四次?

    四次握手可以用但完全沒有必要,建立連接的SYN和確認回復的ACK報文是可以一起發(fā)送的(上文提到過的 捎帶應答),沒有必要分開來增加操作。


    連接超時

    類似超時重傳機制。

    如果客戶端訪問一個距離它很遠,或者由于網(wǎng)絡(luò)繁忙,導致 服務器對于客戶端發(fā)送出的同步報文段沒有應答。 此時客戶端將進行多次重連,若仍然聯(lián)系不上,則通知應用程序連接超時:

    • 超時重連報文一般會有 5 個,這是由 /proc/sys/net/ipv4/tcp_syn_retries 內(nèi)核變量定義的,(加上第一個正常的請求報文也就是說,通知應用程序連接超時之前,最多會發(fā)送 6 個TCP同步報文段請求與服務器連接)。
    • 每次發(fā)重連請求報文段的時間間隔是遞增的:1s 、 2s 、 4s 、 8s 、 16s 、 32s 。也就是 每次重連的超時時間都增加一倍 ,如果不增加的話,那么后五次發(fā)送沒有意義,同樣的時間第一個到不了顯然后五個很大概率從也到不了。

    服務端發(fā)送了SYN和ACK后,沒有收到客戶端的ACK,服務端如何處理?

    說明客戶端可能不在線,此時發(fā)送一個RST重置連接,并且釋放已有資源。


    四次揮手

    • 第一次揮手: 客戶端:我要說的話已經(jīng)說完了。
    • 第二次揮手: 服務端:你要說的我都聽到了,但是我的話還沒說完。
    • 第三次揮手: 服務端:我要說的話也說完了。
    • 第四次揮手: 客戶端:既然我們都說完了,那就結(jié)束通話吧。

    半關(guān)閉狀態(tài) 與 如何檢測連接是否被對方關(guān)閉

    在第二次揮手完成后,客戶端不會再向服務端發(fā)送數(shù)據(jù),但允許繼續(xù)接收對方的數(shù)據(jù)。客戶端這種狀態(tài)為 半關(guān)閉狀態(tài)。 socket網(wǎng)絡(luò)編程接口通過 shutdown函數(shù) 提供了對半關(guān)閉的支持,Linux 也提供了諸多檢測連接是否被對方關(guān)閉的方法,例如:收到結(jié)束報文段時,read 系統(tǒng)調(diào)用返回 0

    為什么不是三次揮手?

    就像上面所說的,處于 半關(guān)閉狀態(tài) 是為了接受對方未發(fā)送完的數(shù)據(jù),但是如果 服務器收到客戶端的FIN報文時湊巧也沒有數(shù)據(jù)要發(fā)送給客戶端了 ,那么客戶端可以從 FIN_WAIT1狀態(tài) 直接進入 TIME_WAIT狀態(tài) ,也就是服務器 不發(fā)送 ACK 報文 ,而是 直接發(fā)送 FIN+ACK 報文 (從)。此時就是三次揮手。


    TIME_WAIT

    什么是MSL?

    MSL(Maximum Segment Lifetime) :最長報文段壽命,它是任何報文在網(wǎng)絡(luò)上存在的最長時間,超過這個時間報文將被丟棄。

    TIME_WAIT狀態(tài)存在的原因

    主動關(guān)閉端 收到 被動關(guān)閉端 的 (FIN,ACK)報文 后并不立刻進入 CLOSED狀態(tài) 。而是等待 2MSL 時間。

  • 防止 舊連接 的 TCP報文段 出現(xiàn)在 新連接 中。
  • 確保 主動關(guān)閉端 最后一次 ACK 報文 能到達 被動關(guān)閉端 ,這樣 被動關(guān)閉端 就可以進入 CLOSED狀態(tài) 。
  • 第二點詳細來說:
    如果過了一個MSL時間,被動關(guān)閉端還沒有收到主動關(guān)閉端第四次揮手報文,被動關(guān)閉端啟動 超時重傳機制 ,重發(fā)第三次揮手報文,主動關(guān)閉端再一次收到第三次揮手報文 ,就知道自己之前發(fā)送的第四次揮手報文丟了,因此重置時間等待計時器為2MSL,并且重發(fā)ACK報文,從而確保雙方都可以進入CLOSED狀態(tài)。

    如果總是能收到第三次揮手報文、但第四次揮手報文一直丟,那也只能一直發(fā)第三次揮手報文了,直到達到超時重傳次數(shù)上限,被動關(guān)閉端不再重傳,直接進入CLOSED狀態(tài)。下面我們分析另一種情況:如果第二次重傳的 第三次揮手報文 丟了怎么辦呢?

    首先明確如果第二次重傳的 第三次揮手報文 丟了,肯定要進行第三次重傳,那就分為下面兩種情況:

  • 若干個(超時重傳次數(shù)上限)第三次揮手報文 都丟在半路上了,那么主動關(guān)閉端早已進入 CLOSED狀態(tài) 。被動關(guān)閉端根據(jù) 超時重傳機制 ,此時TCP認為網(wǎng)絡(luò)或者對端主機出現(xiàn)異常,強制關(guān)閉連接。
  • 如果 第三次重傳第三次揮手報文 到達主動關(guān)閉端,但此時已經(jīng)過了2MSL,那么主動關(guān)閉端會進入 CLOSED狀態(tài) ,此時主動關(guān)閉端不會理會這個報文,而是直接丟棄,不會發(fā)送ACK報文回應。那么其實就跟上一種情況沒什么區(qū)別了。
  • 更多關(guān)于重傳的內(nèi)容可以參考這篇博客。

    避免TIME_WAIT狀態(tài)

    有時候我們希望避免 TIME_WAIT狀態(tài),比如:服務端 主動關(guān)閉連接之后想立刻與 剛斷開的客戶端 重新連接。但是因為服務端總使用同一個 知名服務端口號 與客戶端通信,舊連接的斷開導致這個 知名服務端口號 仍處于 TIME_WAIT狀態(tài) ,導致不能立即重新建立連接。那么有兩種方法避免 TIME_WAIT狀態(tài) :

  • 通過 socket選項 SO_REUSEADDR 來強制進程 立即使用 處于 TIME_WAIT狀態(tài) 的 舊連接 占用的 端口 。
  • 修改內(nèi)核參數(shù) /proc/sys/net/ipv4/tcp_tw_recycle 來快速回收被關(guān)閉的 socket,從而使得 TCP連接 根本就不進入 TIME_WAIT狀態(tài) 。
  • 值得一提的是,由于客戶端一般使用系統(tǒng)自動分配的臨時端口號來建立連接,基于隨機性,臨時端口號一般和程序上一次使用的端口號(還處于TIME_WAIT的連接使用的端口號)不同,因此客戶端程序一般可以立即重啟。

    一臺主機上出現(xiàn)大量的TIME_WAIT是什么原因?如何處理?

    TIME_WAIT狀態(tài)是出現(xiàn)在主動關(guān)閉方的,如果出現(xiàn)大量的TIME_WAIT,就說明有大量的連接被主動關(guān)閉,可能是惡意攻擊或者爬蟲等。處理方法——使用上文中 避免TIME_WAIT狀態(tài)的兩種方法。

    一臺主機上出現(xiàn)大量的CLOSE_WAIT是什么原因?如何處理?

    CLOSE_WAIT狀態(tài)是在 被動關(guān)閉方 收到 主動關(guān)閉方的FIN 后進入的,此時 被動關(guān)閉方 會等待 上層應用 處理積壓數(shù)據(jù),處理結(jié)束后才會發(fā)送FIN。而如果出現(xiàn)大量的CLOSE_WAIT,則說明 被動關(guān)閉方的上層應用處理有問題 ,沒有正確的關(guān)閉SOCKET釋放資源,所以此時就不會發(fā)送FIN,導致一直卡在CLOSE_WAIT。解決方法:查代碼bug,因為問題出在服務器程序里……


    ?;顧C制

    在TCP通信中,如果兩端長時間沒有數(shù)據(jù)往來(默認7200秒),則每隔一段時間(默認75秒),服務端就會向客戶端發(fā)送一個?;钐綔y數(shù)據(jù)報,讓客戶端進行回復,如果多次(默認9次)沒有收到響應,則代表連接已經(jīng)斷開。

    通過?;顧C制來確保如果有一端斷開,能夠及時處理。


    TCP的數(shù)據(jù)類型

    交互/成塊數(shù)據(jù)流

    TCP報文段所攜帶的應用程序數(shù)據(jù)按照長度分為兩種:交互數(shù)據(jù)、成塊數(shù)據(jù)。

    交互數(shù)據(jù)流

    交互數(shù)據(jù)僅包含很少的字節(jié)。使用交互數(shù)據(jù)的應用程序或協(xié)議對實時性要求很高。 如:telnet、ssh等。

    在廣域網(wǎng)上的交互數(shù)據(jù)流可能經(jīng)受很大的延遲,攜帶交互數(shù)據(jù)的微小TCP報文段數(shù)量很多(一個鍵入就可能導致一個TCP報文段),很可能導致網(wǎng)絡(luò)擁塞。交互數(shù)據(jù)流導致的網(wǎng)絡(luò)擁塞可通過Nagle算法解決。

    成塊數(shù)據(jù)流

    成塊數(shù)據(jù)的長度通常為TCP報文段允許的最大數(shù)據(jù)長度(40字節(jié))。使用成塊數(shù)據(jù)的應用程序或協(xié)議對傳輸效率要求很高。比如:ftp。


    帶外數(shù)據(jù)

    概念

    帶外數(shù)據(jù)(Out Of Band):用于迅速通告對方本端發(fā)生的重要事件。因此,帶外數(shù)據(jù)比普通數(shù)據(jù)(也成為帶內(nèi)數(shù)據(jù))有更高的優(yōu)先級,應該總是立即被發(fā)送。帶外數(shù)據(jù)的傳輸可以使用一條獨立的傳輸層連接,也可以映射到傳輸普通數(shù)據(jù)的連接中。 實際應用中,帶外數(shù)據(jù)的使用很少見,已知的僅有telnet、ftp等遠程非活躍程序。

    UDP沒有實現(xiàn)帶外數(shù)據(jù)傳輸,TCP也沒有真正的帶外數(shù)據(jù)。但是TCP利用頭部中的 緊急指針標志緊急指針 兩個字段,給應用程序提供了一種緊急方式。緊急方式利用傳輸普通數(shù)據(jù)的連接來傳輸緊急數(shù)據(jù),來模擬帶外數(shù)據(jù)的傳輸。

    格式

    發(fā)送端一次發(fā)送的多字節(jié)帶外數(shù)據(jù)中只有最后一字節(jié)被當作帶外數(shù)據(jù),其他數(shù)據(jù)被當成普通數(shù)據(jù)。帶有帶外數(shù)據(jù)的TCP報文段頭部將被設(shè)置 URG標志 ,緊急指針指向最后一個帶外數(shù)據(jù)的下一個字節(jié)。

    發(fā)送

    如果含有帶外數(shù)據(jù)的數(shù)據(jù)流很長,TCP模塊將以多個TCP報文段來發(fā)送,每個報文段都設(shè)置URG標志,并且它們的緊急指針指向同一個位置——數(shù)據(jù)流中帶外數(shù)據(jù)的下一個位置,但只有一個TCP報文段真正攜帶帶外數(shù)據(jù)。

    接收

    接收端在接收到URG標志時開始檢查緊急指針,根據(jù)指向位置確定帶外數(shù)據(jù)位置,并將它讀入只有 1 字節(jié) 的 帶外緩存 中。如果上層應用程序沒有及時將帶外數(shù)據(jù)從帶外緩存中讀出,則下一個數(shù)據(jù)流的帶外數(shù)據(jù)(如果有的話)將覆蓋它。

    上面討論的接收過程是默認方式,而當給TCP連接設(shè)置了SO_OBBINLINE選項(詳見socket編程的相關(guān)博客)后,帶外數(shù)據(jù)和普通數(shù)據(jù)一樣存放在 TCP接收緩沖區(qū) 中,這種情況下如何區(qū)分帶外數(shù)據(jù)和普通數(shù)據(jù)呢?

    • 緊急指針可以指出帶外數(shù)據(jù)的位置
    • socket編程接口也提供了系統(tǒng)調(diào)用來識別帶外數(shù)據(jù)

    TCP粘包

    對于TCP來說,每當創(chuàng)建一個 socket 的時候,就會同時在內(nèi)核中創(chuàng)建一個 接收緩沖區(qū)發(fā)送緩沖區(qū) 。

    • 接收緩沖區(qū): 對于接收到的數(shù)據(jù),并非像UDP一樣一條一條往上交付,而是先將接收到的數(shù)據(jù)放入緩沖區(qū),再根據(jù)上層所需要的長度,從接收緩沖區(qū)中取出相應的數(shù)據(jù)交付。

    • 發(fā)送緩沖區(qū): 對于發(fā)送的數(shù)據(jù)并不會直接發(fā)送,而是先存入發(fā)送緩沖區(qū)。如果數(shù)據(jù)過大,則會被拆分成多個TCP數(shù)據(jù)包發(fā)送(成塊數(shù)據(jù)流)。而如果數(shù)據(jù)過小(交互數(shù)據(jù)流),則會在發(fā)送緩沖區(qū)中等待,積累一定的微量數(shù)據(jù)后再從發(fā)送緩沖區(qū)中取出數(shù)據(jù)發(fā)送?!狙舆t發(fā)送機制,亦可選擇不存入緩沖區(qū)直接發(fā)送。】

    • 優(yōu)點: 這種傳輸方式比較靈活,對于多個小數(shù)據(jù),會合并為一條大的數(shù)據(jù)一次性發(fā)送過去,這樣就大大的減少了發(fā)送端IO的次數(shù)和網(wǎng)絡(luò)中的報文數(shù)量。接收方式也很靈活,接收端可以從接收緩沖區(qū)任意讀取想要的數(shù)據(jù),不必像UDP一樣必須交付一條完整的報文。

    • 缺點: 因為數(shù)據(jù)會在緩沖區(qū)中進行合并或者拆分,這就導致了數(shù)據(jù)直接的邊界無法控制,所以TCP交付上層應用程序的這條數(shù)據(jù)可能并非一條完整的數(shù)據(jù),而是半條或者多條數(shù)據(jù),從而導致上層會將多條數(shù)據(jù)按照一條來處理。這也就是TCP粘包問題。

    TCP粘包:TCP可能將多條數(shù)據(jù)按照一條交付給上層應用程序。

    解決方案:自行管理邊界

  • 每條數(shù)據(jù)之間以特殊字符進行間隔(如果數(shù)據(jù)中有該字符可能要轉(zhuǎn)義處理)
  • 數(shù)據(jù)定長傳輸,不夠則補位(數(shù)據(jù)如果過短,則會傳遞大量無用的補位數(shù)據(jù))
  • 應用層協(xié)議頭部定義數(shù)據(jù)長度(這里可以參考 HTTP協(xié)議 和 UDP協(xié)議 的做法)
    • HTTP協(xié)議: 頭部以 \r\n 表示結(jié)束,并且在頭部的 Content-Length 確定正文長度。
    • UDP協(xié)議: 在首部中定義了數(shù)據(jù)報長度,確保每次只交付一條完整的數(shù)據(jù)。

  • 基于TCP的應用層知名協(xié)議

    • HTTP
    • HTTPS
    • SSH
    • Telnet
    • FTP
    • SMTP

    總結(jié)

    以上是生活随笔為你收集整理的网络协议分析 | 传输层 :史上最全UDP、TCP协议详解,一篇通~的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。