關於TCP,我懂的全寫到這裏了

在這裏插入圖片描述

圖中的反覆只是爲了確認對方對你的 "請求" 是否有所 “迴應”.

再比如,當你給朋友寄快遞的時候,你寄完快遞之後將單號拍了下來,發給了你的朋友並告訴他如果你收到這份包裹的話就給我發個消息或者回個電話.
這個快遞發出去無非就是三種情況

  • 1.你的朋友收到快遞,給你發來確認信息
  • 2.你的朋友收到快遞,給你的回覆消息的因斷網而發送失敗(他已經發送過了),你主動向你的朋友詢問情況.
  • 3.你的朋友沒有收到快遞,快遞在運輸過程中丟失(朋友告訴你他沒有收到快遞).

這三種情況中都需要通過你朋友的迴應來確定具體是那種情況,

  • 而這裏的迴應確保了寄件人對📦去向的掌握.

之前學習的通過UDP協議傳輸的信息並不具備這種通過對方迴應來確定對方是否收到包裹的功能

所以我們該怎麼知道對方的接收情況呢?

其實也很簡單,我們需要一種可以通過雙方互動來確認包裹是否正確接收的協議,這就是我們今天將要介紹的TCP協議了。


在這裏插入圖片描述

TCP

報文格式

在這裏插入圖片描述
16位源端口

  • 本機的數據從哪裏出去

16位目的端口

  • 對方的數據從哪裏進去

32位序號字段,32位確認序號

  • TCP連接中傳輸的數據流中每一個字節都有對應的序號.
  • 這兩部分和TCP的ACK機制有關,發送端給應用層收到的數據進行打碼,接收端通過接收到的數據回饋接收狀態

4位數據偏移(首部長度)

  • 指出TCP報文段的數據起始處距離TCP報文段的起始處有多遠,“數據偏移”的單位是32位字(以4字節位計算單位)
  • 標明正文位置

保留字段

  • 該字段主要是爲了以後擴展是使用,其長度爲4位。

控制位
在這裏插入圖片描述

  • URG:當URG=1時,表名緊急指針字段有效,告訴系統此報文段中有緊急數據,應儘快傳送(相當於高優先級的數據)
  • ACK:當ACK=1時確認號有效,ACK=0無效
  • PSH:當PSH=1就提示接收端應用程序立刻從TCP緩衝區把數據讀走
  • RST復位標誌,當RST=1表明TCP連接出現嚴重差錯,必須釋放連接,然後再重新建立運輸連接
  • SYN同步標誌:SYN=1表示這是一個連接請求或連接接收報文
  • FIN結束標誌,用來釋放一個連接, FIN=1表示此報文段的發送端的數據已發送完畢,並要求釋放運輸連接

16位窗口大小

  • 與TCP滑動窗口、流量控制有關,

16位校驗和

  • 校驗和字段檢驗的範圍包括首部和數據兩部分,在計算校驗和時,要在TCP報文前加上12字節僞首部

16位緊急指針字段

  • 指出在本文中緊急數據共有多少個字節
TCP特點
  • TCP是面向連接的運輸層協議
  • 每一條TCP連接只能有兩個端點,每一條TCP連接只能是點對點的(一對一)
  • TCP提供可靠交付的服務
  • TCP提供全雙工通信
  • 面向字節流
    在這裏插入圖片描述

TCP通過檢驗和、序列號、確認應答、重發控制、連接管理、以及窗口控制等機制實現可靠傳輸

  • 所謂的面向有連接的“連接”
    在這裏插入圖片描述

序列號與確認應答(保證可靠性)

我們之前說的寄快遞的例子,你的朋友告訴你他收到了包裹,你才能確定快遞沒有丟失.
而在TCP中,當發送端的數據到達接受主機時,接收端主機會返回一個已收到的消息通知給發送端,這個消息叫做確認應答(ACK),正如你朋友告訴你快遞收到了,而在沒有收到你朋友的回覆的時候,你就會擔心會反問他,這好比一個否定確認應答(NACK)
在這裏插入圖片描述

未收到確認應答的情況分爲兩種

  • 1.數據(包裹)丟失,等待一端時間後(等待多久?)重新發送
    在這裏插入圖片描述
  • 2.數據已接收(快遞已簽收),但是返回的確認應答在途中丟失(確認消息因斷網而沒有發給你).等待一段時間(等待多久?)後重新發送
    在這裏插入圖片描述

在TCP協議中,在沒有收到確認應答的情況下.會將之前的沒有收到ACK的數據重新發送一次.

當然也有可能是網絡原因導致的確認應答延遲到達,

  • 對於這種情況,對於通信中的不同對象而言會造成不同的後果
對象 導致的問題
發送方 按照機制重發一份數據
目標主機 反覆接收相同的數據
目標主機上層應用 必須放棄重複的數據包

爲了解決這種情況帶來的問題,我們需要引入一種既能識別已經接收數據,又能夠判斷是否需要接收該數據的機制

  • 上述這種確認應答處理、重發控制以及重複控制等功能都可以通過序列號實現.

序列號是按照順序給發送的數據的每一個字節都打上一個,接收端查詢接收數據TCP首部中的序列號和數據長度,並將下一次應該接收的序號作爲確認應答返回給發送方.

  • 互動圖
    在這裏插入圖片描述
  • 操作端模擬圖
    在這裏插入圖片描述
  • 確認應答序號的含義是當前序號之前的數據已經收到了,希望收到的下一條數據就是從確認序號開始的

超時重發如何確定

  • 超時重發是指在重發數據之前,等待確認應答到來的那個特定時間間隔,如果超過了這個時間仍未收到確認應答,發送端就會重新發送未收到確認應答的數據,那麼這個超時重發的等待時間該怎麼確定呢?
    在這裏插入圖片描述
    超時重發的計算既要考慮往返時間又要考慮偏差,是因爲同一個報文在不同的網絡環境中傳輸的速度是不同的.而TCP/IP 的目的是在於即使在不同的網絡環境下也要對網絡流量進行控制,不造成浪費.

  • 在Unix和Windows系統中,超時都是以0.5秒爲單位進行控制的,因此重發超時都是0.5秒的整數倍,不過,由於最初的數據報不知道這個時間,所以其重發超時一般設置爲6秒左右.

數據被重發之後若還是收不到確認應答,則需要再次重發,此時等待確認應答的時間是以2的整數倍的方式延長的.

當然在網絡中也不能對同一份數據反覆進行重發,當這份數據的重發次數到達限制之後,仍然收不到任何確認應答.就會判斷爲網絡或對端主機發生異常,強制關閉連接.並通知本端應用層通信異常強行終止連接.

連接管理

建立連接(三次握手)
  • 用處

  • 1.確定雙方的交付能力

  • 2.指定初始序列號,爲可靠傳輸做準備

  • 3.交互保密機制

  • 握手過程(粗略的說法)

  • 1.客戶端給服務器發送一個SYN報文

  • 2.服務器收到SYN報文後,會應答一個SYN+ACK報文

  • 3.客戶端收到SYN+ACK報文後,迴應一個ACK報文
    在這裏插入圖片描述

  • 握手過程(精確的說法)
    在這裏插入圖片描述

  • 1.客戶端發送SYN報文,指定序列號ISN,處於SYN_Send狀態

  • 2.服務端把SYN作爲應答,指定ISN,把客戶端的ISN+1作爲ACK值發送給客戶端,此時服務器處於SYN_RECV狀態

  • 3.客戶端發送一個ACK報文,此時客戶端處於established狀態

  • 4.服務器收到ACK報文之後也處於established狀態

補充:

  • 半連接隊列:服務器第一次收到客戶端的SYN之後,就會處於SYN_RCVD狀態,此時雙方還沒有完全建立其連接,服務器回把這種狀態下請求的連接放入一個隊列,我們把這個隊列稱爲半連接隊列(用於保存處於SYN_SEND 和 SYN_RECV狀態的請求)
  • 全連接隊列:已經完成三次握手,建立起連接的就會放到全連接隊列中,如果隊列滿了就會出現丟包的可能性.

在該過程中的客戶端在發送確認應答的同時也發送了建立連接的請求(SYN包)

  • 因爲SYN和ACK都是內核控制發送的,所以可以進行合併
斷開連接(四次揮手)

端開連接的過程(粗略)
在這裏插入圖片描述

  • 1.客戶端給服務器發送一個FIN結束報文(分手通知,調用close()函數)
  • 2.服務器給客戶端發送一個ACK確認應答(對方告訴你他知道了,收到FIN報文,理解返回ACK)
  • 3.服務器也給客戶端發送一個FIN結束報文(對方同意分手,也向你提出分手,調用close())
  • 4.客戶端給服務器發送一個ACK確認應答(你收到對方的分手通知,斷開連接)
  • 精確一點的說法

剛開始兩者都處於ESTABLISHED狀態

  • 假設客戶端先發起關閉請求
    在這裏插入圖片描述

  • 1.第一次揮手:客戶端發送一個FIN報文,報文中會指定一個序列號,此時客戶端處於FIN_WAIT1狀態

  • 2.第二次揮手:服務器收到FIN之後,會發送ACK報文,且把客戶端的序列號值+1作爲ACK報文的序列號值,表明已經收到客戶端的報文了,此時服務器處於CLOSE_WAIT2 狀態

  • 3.第三次揮手:如果服務器也想斷開連接了,向客戶端發送FIN報文,且指定一個序列號,此時服務器處於LAST_ACK 狀態

  • 4.第四次揮手:客戶端收到服務器端的FIN報文後,發送一個ACK報文作爲應答,且把服務端的序列號值+1作爲自己ACK報文的序列號值,此時客戶端處於TIME_WAIT 狀態.需要過一陣子(2MSL)以確保服務端收到自己的ACK報文後纔會進入CLOSED 狀態

  • 5.服務器收到ACK報文之後,就處於關閉連接了,處於CLOSED狀態

  • FIN是函數close()進行觸發的,由程序控制,而ACK是內核發送的.

  • 第一個ACK和第二個FIN不一定能合併

  • 連接管理的綜合圖
    在這裏插入圖片描述

  • 重要的TCP狀態

  • 1.LISTEN狀態:服務器已啓動,隨時可以連接

  • 2.ESTABLISHED狀態:連接建立成功,隨時可以通信

  • 3.CLOSED_WAIT等待調用close()函數,對端已經執行過close()函數

如果服務器端出現大量的CLOSE_WAIT狀態,

  • 代碼中忘記調用close
  • 4.TIME_WAIT狀態:

爲什麼客戶端發送ACK之後不直接關閉,而要等一會才關閉?

  • 因爲最後發送的ACK也存在丟包的可能,所以客戶端需要確保服務器已經收到了客戶端發送的ACK
  • 若最後發送的ACK丟包了,那麼服務器端收不到確認應答就需要重發FIN報文給客戶端,客戶端再次收到FIN報文之後,就知道之前的ACK報文丟失了,重新發送ACK報文
  • TIME_WAIT會保持一個報文的來回時間(2MSL).MSL表示網絡中的兩個結點之間,傳輸一個數據所經歷的最大時間.過了這個時間客戶端沒有再次收到FIN報文,就表示對方成功接收了ACK報文,此時處於CLOSED狀態

滑動窗口與重發控制

TCP以1個段爲單位,每發一個段就需要進行一次確認應答的處理,這樣再等待ACK的這段時間裏發送端是閒置的,那麼就會使得TCP的傳輸效率低下.

爲了解決傳輸效率低的問題,TCP引入了窗口這個概念.即使在往返時間比較長的情況下,他也能控制網絡性能的下降.因此確認應答不再是以每個分段,而是以更大的單位進行確認時,轉發時間將會被大幅度的縮短.也就是說,發送端主機在發送了一個段之後不必要一直等待確認應答,而是繼續發送(在窗口大小夠用的情況下)

在這裏插入圖片描述

窗口大小:指無需等待確認應答而可以繼續發送數據的最大值(真實的窗口大小值爲流量控制和擁塞控制兩者中的較小者).
發送前四個段的時候,不需要等待任何ACK,直接發送

  • 收到第一個ACK後,滑動窗口向後移動,繼續發送第五個段的數據,依次類推.
  • 操作系統內核爲了維護這個滑動窗口,需要開闢發送緩衝區來記錄當前還有那些數據沒有應答,只要確認應答過的數據,才能從緩衝區刪掉
    在這裏插入圖片描述

在這種機制下會出現的兩種機制

  • 情況一:數據包已經到達,返回的ACK丟失
    在這裏插入圖片描述

  • 這種情況下,部分ACK丟了並不要緊,因爲可以通過後續的ACK進行確認
    例如:在發送了1~5000個自己的數據後均沒有收到ACK,但是再發送了5001 ~ 6000 之後主機A收到ACK(下一個是6001),說明前6000個字節主機B 已經收到了,就不需要再去重發之前的數據了

  • 情況二:數據包就直接丟了
    在這裏插入圖片描述
    當某一段報文丟失後,發送端會一直收到序號爲丟失段的確認應答
    如果發送端主機連續三次收到同樣內容的確認應答,就會將對應的數據重新發送
    當接收端收到丟失段的確認應答後,再次返回的確認應答就是之前已經接收過到數據,被放到了接收端操作系統內核的接收緩衝區中,如上圖中的7001,這種機制被稱爲"高速重發控制(也叫"快重傳")"

流量控制

接收端處理數據的速度是有限的,如果發送端一直保持高速發送,就會導致接收端的緩衝區很快就被填滿,之後如果接收緩衝區中的數據沒有被讀走(接收端緩衝區沒有空餘空間),發送端繼續發送數據就會造成丟包,繼而引起包重傳等一系列的連鎖反應

因此TCP支持根據接收端的處理能力,來決定發送端的發送速度,這個機制叫做流量控制

  • 接收端將自己可以接收的緩衝區大小放入TCP首部中的"窗口大小"字段,通過ACK報文通知發送端.

  • 接收端一旦發現自己的緩衝區快滿了,就會將窗口大小設置成一個更小的值通知給發送端

  • 發送端接受到之後,就會減慢自己的發送速度

  • 如果接收端緩衝區滿了,接收端將會將窗口置爲0,這時發送方不再發送數據,但是需要定期發送一個窗口探測數據段,讓接收端把窗口大小告訴發送端
    在這裏插入圖片描述

  • 如上圖中,當接收端收到從3001號開始的數據段後其緩衝區滿了,需要暫停數據的接收.之後,在收到發送窗口更新通知後通信才能繼續進行.但是這個更新通知可能在傳送途中丟失,所以發送端會時不時的發送一個叫做窗口探測的數據段,此數據段僅含一個字節以獲取最新的窗口大小信息

TCP協議報頭中的窗口大小字段,這個字段是和接收緩衝區的空餘大小相關聯的

擁塞控制

在這裏插入圖片描述

  • 爲什麼會引入擁塞控制?
    因爲,TCP滑動窗口雖然能高效可靠的發送大量的數據,但是在某個連接剛建立的時候並不清楚網絡的擁塞狀況,發出數據後遲遲收不到ACK,就可能進行重發.在不清楚網絡狀態的情況下就進行重發的話,會使擁塞情況更加嚴重,所以需要我們設計出一種可以控制網絡擁塞情況的機制
    在這裏插入圖片描述
    網絡中判定擁堵的依據:在交互過程中是否出現了丟包現像,若出現丟包,則認爲比較擁堵。
慢啓動(網絡擁堵的解決)

TCP 引入了慢啓動 機制,先發送少量數據,查看當前網絡的擁堵情況,再決定按照多大的速度傳輸數據.

  • 沒有出現丟包就按指數形式增大窗口.若窗口大小達到閾值之後就開始線性增長,當窗口達到某個值後就會發生丟包,一旦發生丟包現像就認爲網絡出現擁堵,就立刻將窗口大小減小到一個很小的值.之後重複慢開始過程

在這裏插入圖片描述

  • 當TCP開始啓動的時候,慢啓動閾值等於窗口最大值
  • 每次發生超時重傳,慢啓動閾值就會減半,同時將擁塞窗口置爲1

真實的窗口大小值爲流量控制和擁塞控制兩者中的較小者

延時應答(提高傳輸效率)

  • 如果在收到數據報之後立即返回ACK,則有可能在ACK返回和下一次數據發送到來的這段時間內接收端的緩衝區已經比返回ACK的窗口大小要大了,這就導致網絡資源利用率的降低

在這裏插入圖片描述

那麼我們可以在第一次接收到數據後不立即返回ACK,而是暫緩一會再發送ACK,可能其在暫緩發送的這段時間裏接收緩衝區中的數據就會拿走了,則ACK中返回的窗口大小就變大了,這個過程就是延時應答

那麼暫緩的這段時間是多長時間呢?

  • 數量限制:每隔N個包就應答一次
    在這裏插入圖片描述
    上圖中,每發兩個包就應答一次
  • 時間限制:超過最大延遲時間就應答一次

捎帶應答

依賴於延時應答

  • 在延時應答的基礎上,引入的一個機制

TCP四次揮手有沒有可能是三次呢?

有可能,因爲稍等應答支持這件事情.
因爲延時應答的存在,可能會使得第二次揮手和第三次揮手時間重合了,導致FIN和ACK在同一個包中發送給對方。

在這裏插入圖片描述

面向字節流

  • 創建一個TCP的socket, 同時在內核中創建一個 發送緩衝區 和一個 接收緩衝區;
    在這裏插入圖片描述

  • 調用write時, 數據會先寫入發送緩衝區中;

  • 如果發送的字節數太長, 會被拆分成多個TCP的數據包發出;如果發送的字節數太短, 就會先在緩衝區裏等待, 等到緩衝區長度差不多了, 或者其他合適的時機發送出去;

  • 接收數據的時候, 數據也是從網卡驅動程序到達內核的接收緩衝區;然後應用程序可以調用read從接收緩衝區拿數據;

  • 另一方面, TCP的一個連接, 既有發送緩衝區, 也有接收緩衝區, 那麼對於這一個連接, 既可以讀數據, 也可以寫數據. 這個概念叫做 全雙工

  • 由於緩衝區的存在, TCP程序的讀和寫不需要一 一匹配,

例如:
寫100個字節數據時, 可以調用一次write寫100個字節, 也可以調用100次write, 每次寫一個字節;
讀100個字節數據時, 也完全不需要考慮寫的時候是怎麼寫的, 既可以一次read 100個字節, 也可以一次read一個字節, 重複100次;

  • 發送緩衝區調用send()本質上是把用戶的數據拷貝到內核的發送緩衝區中,再由內核按照滑動窗口的方式把數據批量發送到對端,如果丟包就會重傳對應的數據
  • 接收緩衝區:收到的數據先到達接收緩衝區,用戶代碼從接收緩衝區中都讀走(read/recv)數據後,纔會把數據讀走後纔會清除掉,接收緩衝區也會幫助用戶進行數據的去重

粘包問題

面向字節流相關,應用程序如何能夠一次取出一個完整的應用層數據報,從應用層的角度來解決這個問題,只要能夠確定數據報和數據報之間的邊界就可以了

確認邊界的兩種方式

  • 1.分隔符
  • 2.指定長度

TCP異常情況

TCP小結

  • 可靠性:
  • 確認應答/超時重傳
  • 連接管理
  • 傳輸效率
  • 滑動窗口

流量控制/擁塞控制
延時應答 / 捎帶應答

TCP/UDP的對比

  • UDP

  • 無連接

  • 不可靠

  • 面向報文(對上層來的報文不做拆分/合併,只是封裝了UDP首部)

  • 支持一對多,多對一

  • TCP

  • 面向有連接

  • 可靠的

  • 面向字節流(把報文看成字節流,拆分組織成大小不等的數據塊)

  • 只能一對一

  • 1.如果需要可靠性(比如外網複雜的網絡環境),優先考慮TCP

  • 2.如果網絡結構本身比較簡答,可靠性比較高(機房內網),對傳輸效率要求更高,優先考慮UDP

  • 3.如果你要傳輸的數據報較大,TCP(UDP的包有最大長度64K)

  • 4.如果需要廣播的話,只能使用UDP,TCP不能廣播

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章