計算機網絡(三) - TCP協議詳解


上一篇:計算機網絡(二)- TCP/IP協議群介紹

1、概述

​ TCP協議全名是 Transport Control Protocol ,是一個可以提供 可靠的、支持全雙工、連接導向的協議,因此在客戶端和服務端之間傳輸數據的時候,是必須先建立連接的。

image-20211202230056757

1.1、什么是建立連接

  • 連接本身是個虛擬、抽象的概念。他能讓兩個通信的程序之間確保彼此都在線
  • 建立連接可以加快相應請求的速度
  • 連接也被稱為 會話(Session)
  • 建立連接可以使得通信更加的穩定、安全
  • 但是同樣建立連接也會消耗相應的資源

1.2、單工、半雙工、全雙工

  • 單工: 任何時刻數據只能單向傳輸
  • 半雙工:允許數據在兩個方向上傳輸, 但是在某一個時刻(同一時刻),只允許數據在一個方向上傳輸。
  • 全雙工: 任何時刻數據都可以雙向傳輸。

image-20211202231220450

1.3、可靠性

  • 可靠性是為了保證數據的無損傳輸
  • 使用無序的數據恢復原有順序
  • 多播時每個接收方都獲得無損的副本。

2、特點

  • 1、基於連接的(點對點的通信)

    • 傳輸數據之前是要建立好連接的
  • 2、是雙工通信的

    • TCP協議一旦建立連接, 就可以在連上上實現雙向的通信
  • 3、基於字節流而非報文--保證了TCP協議的可靠性

    • 將數據按字節大小進行編號,接收端通過ACK來確認收到的數據編號,通過這個機制保證TCP協議的有序性和完整性
  • 4、擁塞控制

    • TCP協議通過 慢啟動、擁塞避免、擁塞發生、快速恢復 在不同的過程中的算法來控制擁塞的
  • 5、流量控制能力

    • 通過滑動窗口控制數據的發生速率,滑動窗口的本質是動態緩沖區,接收區根據自己的能力在 TCP 的請求頭header中動態調整窗口大小,通過ACK應答包通知到給發送端,發送端根據窗口的大小調控發送速率。

3、TCP協議詳解

在解釋TCP工作流程之前呢, 先解釋一下幾個名詞,這樣更有助於我們去了解其過程。

3.0、TCP首部信息組成以及各個部分的作用

下圖是TCP協議報文段的組成圖片

image-20211202233308672

image-20211202235746756

3.0.1、源端口和目的端口
  • 源端口,用來存放 發送TCP報文的進程對應的端口號。占 2個字節(16位)
  • 目的端口,用來存放 接受TCP報文段的進程對應的端口號。 占 2個字節(16位)
3.0.2、32位序列號 Sequence Number
  • 占用4個字節(一個字節(byte)8個比特位(bit))。
  • TCP的序列號對數據包進行標記,以便達到目的地后重新組裝數據包,假設當前序列號為 s ,發送數據長度為 l,則下一次發送數據時的序列號為 s+l
  • 在建立連接時通常由計算機生成隨機數作為序列號的初始值。
3.0.3、32位確認號 Acknowledgement Number
  • 占用 4個字節(一個字節(byte)8個比特位(bit))
  • 是有接收端計算機使用,用於重組分組的報文成最初形式。
  • 如果設置了ACK控制位, 那么這個值表示准備接受的下一個包的序列號
3.0.4、數據偏移 offset
  • 占用4位,即0.5個字節
  • 這部分實際上是指出TCP報文的首部的長度,即TCP報文段數據起始位置距離TCP報文的起始位置有多遠(這里指 TCP拆包后的報文段的起始位置 與 TCP整個報文的起始位置有多遠)
3.0.5、保留字 Reserved
  • 占6位,即 0.75個字節
  • 保留為以后使用,當前是值為零。
3.0.6、標志位 Tcp Flags
  • 每個標志位占1 位,一共6個標志位 。即 1.5個字節。
  • URG - 緊急指針有效標識
    • 此標志位用來表示TCP包的緊急指針域有效,用來保證TCP連接不會被終端,並且督促中間層設備要盡快處理這些數據。相當於告訴接收端,有高優先級的數據。
  • ACK - 確認序號有效標識
    • 只有當ACK=1的時候,確認號字段才有效。
    • ACK=0的時候,確認號是無效的。
  • PSH - 用來表示接收方應盡快將這個報文段交給應用層
    • 接收到PSH = 1 的TCP報文段, 應盡快的交付接收報文段的應用進程, 而不再等待整個緩存都填滿后再交付
  • RST - 重建連接標識
    • RST = 1 時,表明TCP連接出現嚴重錯誤(如由於主機崩潰或其他原因),必須釋放連接,然后再重新簡歷連接。
  • SYN - 表示同步序號,用來建立連接。
    • SYN = 1 時,表示這是一個連接請求或者連接接受請求。
  • FIN - 發送完成任務標識,用來釋放一個連接
    • FIN = 1 表明此報文段的發送端和數據已經發送完成了
3.0.7、窗口大小 Window Size
  • 占 16位 即兩個字節
  • 該字段表明指出了現在允許對方發送的數據量,他告訴對方本端TCP連接緩沖區還能容納多少字節的數據,這樣對方就可以控制發送數據的速度。
  • 窗口大小的值 指的是 從本報文段的首部中的確認號算起, 接方法目前允許對法發送的數據量。
3.0.8、校驗和 TCP Checksum
  • 占用16位,即兩個字節。
  • 由發送端填充,接收端對TCP報文段執行CRC算法,以校驗TCP報文段在傳輸過程中是否損壞,如果損壞則丟失。
  • 檢驗范圍包括首部和數據兩個部分
  • 這也是TCP可靠性的一個重要保障。
3.0.9、緊急指針 Urgent Pointer
  • 占用16位,即兩個字節
  • 這部分僅在標志位 URG = 1的時候才有意義,他指出本報文段中的數據的字節數。
  • URG = 1 時,發送方TCP就把緊急數據插入到本報文段數據的最前面,而在緊急數據后面任然是普通數據。
  • 因此, 緊急指針指出了數據的末尾在報文段中的位置。

3.1、TCP協議的三次握手四次揮手

參考文檔 :https://www.cnblogs.com/qdhxhz/p/8470997.html

先看一下TCP從建立連接到傳輸數據到斷開連接的完整過程

image-20211204110002227

3.1.0、三次握手建立連接的過程

image-20211204100545362

流程如下:

  • 第一次握手(由客戶端發起的)

    • 客戶端發送 SYN=1 seq = x 的請求建立連接的報文
      • (SYN 標志位中的同步序列號,用來建立連接的)
      • seq 是 32位序列號 Sequence Number,即在建立連接的時候, 隨機生成的初始序列號x。
    • 此時,客戶端進程進入了 SYN-SENT(同步已發送狀態)狀態
    • 此次建立連接的報文是不能攜帶數據的。
  • 第二次握手(由服務端發起)

    • 服務器接收到請求建立連接的報文后,如果同意連接, 則發出確認報文。
      • 標志位 ACK = 1, 確認號 ack = x+1,這個確認號為 x+1 就是基於上面請求的的seq隨機生成的初始序列號+1得出的。
      • 標志位 SYN = 1, 確認號 seq = y , 這個seq 也是服務端自己隨機生成的一個初始序列號。
    • 此時 , 服務器進程進入到 SYN-RCVD(同步收到狀態)的狀態。
    • 這個報文也不能攜帶數據。
  • 第三次握手(由客戶端發起)

    • 客戶端收到 服務器發送的的確認報文后, 還要再向服務器發送確認報文。
      • 標志位ACK = 1 , 確認號ack = y+1 ,序列號 seq = x+1
    • 此時 TCP連接建立,客戶端和服務端都進入 ESTABLISHED(連接已建立) 狀態。
  • 舉例解釋一下為什么要三次握手

    • 當客戶端發送第一個連接的請求報文, 但是由於網絡不好,這個請求沒有立即到達服務器, 而是在某個節點停留了,知道某個時間才到達服務器,本來這已經是一個失效的報文了, 但是 服務端接收到這個請求報文后,還是會像client 發出確認報文,表示同意建立連接。
    • 假設 不采用三次握手,那么只要服務器發出去確認報文,新的連接就建立了,但是其實這個請求已經超時並失效了,客戶端是不會理睬服務器的確認信息的 ,也不會向服務端發送確認的請求。
    • 但是此時的服務器是已經認為連接建立了, 換句話說就是處於ESTABLISHED(連接已建立)的狀態,並且一直在等待客戶端發來數據。
    • 這樣的話, 服務器端就有很多資源浪費了。
    • 而采用三次握手的話, 服務端如果收不到確認報文話,就知道客戶端沒有服務端建立連接不成功了。
3.0.2、TCP 數據傳輸過程

客戶端 與 服務端 建立連接之后,就可以相互傳輸數據了。

  • 如上圖所示,正常傳輸數據的過程如下:

    image-20211204105540187

    • 主機A 開始發送數據的時候,假設初始的 seq = 1200 ,滑動窗口大小為100,向主機B發送數據傳遞
    • 主機B在完全接收到數據后, 為了確認收到 ,需要向主機A 發送ACK包,設置的 值為 1200+100+1 .
      • ACK = seq + 傳遞數據的字節數 + 1
    • 主機A在接收到 主機B 的確認信息后,開始發送下個報文, 此時 seq = 1301 ,同樣滑動窗體的大小為100的數據。
    • .......
    • 注: 與 三次握手協議相同, 最后加1 是為了告訴對象要傳遞 seq信號的。
  • 如上圖所示 , 數據丟包的情況過程如下:

    image-20211204110857472

    • seq = 1301 數據包向主機B 傳遞 100字節的數據,但中間發生了錯誤,主機B 未收到。
    • 經過一段時間的等待后, 主機A 任然未收到 Seq = 1402 的確認號,此時就會嘗試數據重新傳遞。
    • 為了完成數據包的重傳, TCP Socket套接字每次發送數據包時都會啟動定時器, 如果在一定時間內沒有收到目標主機的傳回的ACK包, 那么定時器超時, 數據包會重傳。
3.0.3、四次揮手斷開連接

image-20211204135443345

  • 首先TCP連接斷開, 是一個客戶端主動關閉, 服務端被動關閉的過程。

  • 關閉連接需要經過4次會話,具體的流程如下:

    • 第一次揮手
      • TCP 連接的客戶端發送一個 標志位FIN(結束)=1 的報文,用來請求關閉客戶端到服務端的連接。
      • 客戶端進程發出釋放連接的報文。 釋放連接報文的首部,FIN =1,其序列號是 seq = u (序列號等於前面已傳送過來的數據的最后一個字節的序號加1)
      • 客戶端在發送釋放連接的請求后進入FIN-WAIT-1(終止等待1)的狀態。
      • TCP協議規定, FIN 報文即時不攜帶數據也要消耗一個序號。
    • 第二次揮手
      • 服務端收到客戶端發送的FIN報文時,客戶端會先發送一個 ACK(確認)的報文給客戶端。
      • 服務端回復的ACK報文中, ACK = 1 seq = v , ack = u + 1
        • ACK = 1 表示確認報文
        • ack = u + 1 是針對上面第一次揮手服務端的 seq = u 再加上1
        • seq = v 是服務端自己隨機生成的序列號。
      • 此時,服務端就進入到CLOSE-WAIT(關閉等待狀態)
        • TCP 會通知上層應用進程, 客戶端向服務器的方向就釋放了。
        • 此時,是處於半關閉狀態, 即客戶端已經沒有數據要發送了, 但是服務器若要發送數據,客戶端依然要接收。
        • 這個狀態還要持續一段時間, 也就是整個CLOSE-WAIT狀態持續的時間。
      • 客戶端 在接收到服務器的 斷開連接的確認ack報文后,此時
        • 客戶端就進入了FIN-WAIT-2(終止等待2)狀態,等待服務器發送連接釋放報文。
    • 第三次揮手
      • 服務端發送完 ACK 報文后,在確認數據傳輸完畢后,會發送一條 FIN(結束)的報文到客戶端。
      • 由於處於半關閉狀態, 服務器可能又發送可一些數據,假定此時的序列號為 seq = w
      • FIN = 1 , ack = u + 1
      • 此時, 服務器就進入 LAST-ACK(最后確認)狀態了。
    • 第四次揮手
      • 最后, 客戶端收到了服務端的FIN = 1 的報文后,知道客戶端已經沒有數據需要傳輸了,由客戶端最后再向服務器發送 ACK = 1 的確認報文。並 ack = w(服務端發送的seq)+1 以及 seq = u+2.
      • 此時 客戶端進入 TIME-WAIT(時間等待)狀態。
      • 注意,此時TCP 連接還沒有釋放, 必須經過 2 ** MSL(最長報文段壽命) 的時間后, 當前客戶端撤銷相應的TCB后才進入 CLOSED狀態。
      • 服務器端只要接收到客戶端發送的確認, 就立即進入CLOSED狀態。
      • 綜上所述: 服務器端結束TCP連接的時間要比客戶端早一些。
  • 思考(一):為什么是 4次揮手?

    • 首先肯定是為了保證數據能個完成全部的傳輸過程。
    • 當關閉連接時, 當收到對方發送的FIN報文是, 僅僅表示對方沒有數據發送給你了。但未必是你發送給對方的數據是否全部發送完畢了,所以你未必可以馬上就關閉SOCKET 套接字。所以你可能需要繼續傳輸數據給對方。數據發送完完畢后再發送一個FIN報文給對方。 所以此時服務端的 ACK報文 和 FIN 報文是分開來發送的。
  • 思考(二):數據傳輸過程中客戶端突然掛了怎么辦?
    • 正常連接時, 客戶端會掛了,如果沒有措施處理這種情況的話, 那么就會出現客戶端和服務端出現長時間空閑掛起。
    • 解決辦法就是在服務器端設置保活計時器,每當服務器收到客戶端的消息, 就將計時器復位。計時器的超時時長通常設置為2小時。
    • 如果服務器超過2小時沒收到客戶端的消息, 他就發送探測報文段,若發送10個探測報文段, 每個相隔75s,還沒有相應, 就認為客戶端出現故障了, 因而終止該連接。
  • 思考(三): 為什么客戶端最后還要等待 2MSL?
    • MSL(Maximun Segment Lifetime) 最長報文壽命

    • 1、保證客戶端發送的最后一個ACK報文能夠順利服務器,因此這個報文在數據傳輸過程中可能會丟失

      • 站在服務器角度來看,服務器已經發送了FIN+ACK 報文請求斷開了, 客戶端沒有給我相應,應該是我發送的請求斷開的報文,客戶端沒有接收到, 於是服務器又會重新發送一次,而客戶端就可以再2MSL時間內, 重傳這個報文,接着給出ACK報文后, 會重啟2MSL計時器。
    • 2、防止已經失效的連接請求報文段出現在在本連接中。

      • 客戶端發送完最后一個確認報文后,在這個2MSL時間中, 就可以是本連接吃的時間內所產生的所有報文段都從網絡中小時。這樣新的連接中不會出現連接的請求報文。
    • 3、那么等待2MSL 就一定沒問題了嘛?

      • 不,還有一個超時機制, 超時了,即使沒有收到回復也會關閉連接。
  • 思考(4): SYN(洪流)攻擊(后面有機會再補充)?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM