OSI參考模型詳解之玩轉傳輸層

Sentiger發表於2021-04-27

在OSI參考模型中,傳輸層是相對接近使用者的一層,在進行網路程式設計的時候,是必不可少必須要了解的一層。對於傳輸層的協議有UDP協議,TCP協議,接下來將詳細講解這兩種協議的作用以及底層原理。幫助大家更好的深入瞭解傳輸層的內容。

在傳輸層中進行處理過的資料叫做資料段(Segment),是雙工通訊的(對於後面理解TCP3次握手和4次揮手有幫助)就是服務端可以主動和客戶端通訊,客戶端端同時也能與服務端傳送訊息,理解是兩條通道。

1. 為啥要使用TCP

對於使用者傳送重要資料,則希望資料要麼傳送到對方,要麼傳送失敗,總要有個明確結果。不然使用者傳送資料出去了,有沒有被接收方接收到這些都不能確定的話,純屬在一個黑匣子裡面,這樣的話使用者很不放心,所以TCP就是來解決這個問題的。

2. TCP概述

傳輸控制協議(TCP,Transmission Control Protocol)是一種面向連線的、可靠的、基於位元組流的傳輸層通訊協議,由IETF的RFC 793 [1] 定義。【百度百科】

3. TCP結構

在OSI每一層中都是有協議支援的,所以想了解TCP,就要去了解TCP是如何設計的,類別與應用程式程式碼中對於某個功能的實現,瞭解內部定義的一些細節方能更好的瞭解其原理。
在這裡插入圖片描述

3.1 TCP首部

首部佔用20~60位元組,其中20個位元組是基礎欄位資訊,40個位元組是一些補充資訊。頭部定義了以下欄位

  • 來源埠號(佔用2個位元組16位)進而知道埠號的範圍是2^16-1=65535
  • 目的埠號(佔用2個位元組16位)
  • 序列號(Sequence Number):傳輸資料的一個位元組編號
  • 確認號(Acknowledge Number)對於傳送方的一個回應,只有當標誌位ACK=1的時候才有效
  • 資料偏移:佔用4位(0101~1111)。
  • 保留位:佔用3位,目前是不用的
  • 標誌位(Flag):佔用9位,用來標識傳送什麼樣型別的資料
  • 視窗(Window)佔用2個位元組,用來流量控制
  • 校驗和(CheckSum)佔用2個位元組,用來校驗資料的完整性
  • 緊急指標:佔用2個位元組,只有當標誌位URG=1的時候才有效
  • 選項:佔用40個位元組。後面會詳細介紹。

3.1.1 源埠/目的埠

在傳輸層中,會將資料進行封裝。其中就會加入源埠號,和目的埠號。其實這兩個欄位其實到後面就會理解到是為了資料傳輸能夠準確的送到到哪個埠。並且不同的埠號之間資料不串通。通過網路層封裝的源IP+源埠+目的IP+目的埠表示一個socket。

  • 佔用2個位元組16位
  • 最大的數量也=2^16-1=65535
  • 所以客戶端服務端中埠號最大就是65535

3.1.2 序列號(Sequence Number)、確認號(Acknowledge Number)

傳輸的資料的第一個位元組編號。
因為一個大應用層資料要想傳送給對方,一次性是不能傳送的,所以需要切割成一段一段的在網路中傳輸給到對方。對方接受到資料要將資料都重新組合呀!所以他們要知道如何組合,並且接受到的資料段中,有沒有丟失的段。

  • 佔用4個位元組
  • 建立連線之後,代表TCP資料的第一個位元組編號

TCP三次握手序列號跟蹤
使用wireshark進行抓包

  1. 客戶端發起服務端連線
    傳送標誌位SYN
    在這裡插入圖片描述
    a) 客戶端第一次傳送建立連線請求,會給到一個初始化序列號到服務端,表明以後傳送資料的時候,資料段第一個位元組的序列號為初始化序列號+相對的序列號
    b) 相對序列號:(因為是資料段第一個位元組的序列號)第一次建立連線,因為傳送的資料長度為0,所以相對序列號為0嘛

  2. 服務端確認客戶端連線,並也想建立和客戶端的連線[ACK+SYN]
    在這裡插入圖片描述

  3. 客戶端確認服務端的請求連線
    因為服務端傳送了請求連線,那我一定要回一個才對嘛,要不然服務端也不知道到底客戶端有沒有收到自己傳送的請求。
    在這裡插入圖片描述

  4. 正式傳送http請求
    在這裡插入圖片描述

  5. 服務端確認收到了客戶端傳送的資料
    上面說了,TCP是可靠的,所以對於每次傳送資料一定要有個確認,不管失敗還是成功,如果沒有收到,則在有效的規則內一直髮送。(有效規則後面會介紹,例如總不能一直無限傳送吧)
    a) 確認收到了86個位元組
    b) Ack=87,接下來傳送
    在這裡插入圖片描述

  6. 接下來也是一樣的分析,服務端給客戶端傳送資料,可自行分析

總結

  1. 傳送建立請求連線方會初始化一個序列號給相對應的傳送方
  2. Seq序列號是建立完成傳送內容(內容資料,不是首部)的第一個位元組編號。
  3. Ack確認號是對傳送方傳送的資料的確認,並且告訴傳送方接下來如果傳送資料則傳送Ack的序列號資料

3.1.3 資料偏移

  • 佔用4位
  • 範圍 0101~1111 =>十進位制(4到15)
  • 資料部分相對首部最前面偏移了多少。反向的就是說首部佔用了多大。
  • 偏移量*4=首部長度(20到60位元組)
  • 4表示含義:4其實是一個係數,約定好的,因為4位最大也就是15,但是15又不能表達真實的資料大小,兩種方案,要麼位數增加點,這樣就要多點空間。要麼就約定好一個係數,真實資料=偏移量*係數。 後面還有很多這樣的設計。

3.1.4 標誌位

因為傳送資料段的時候,有很多中情況,例如這次是傳送資料,還是建立連線,還是斷開連線等,所以為了區分傳送的資料是表示什麼含義,進而有了標誌位的出現。不同的標誌位表示不同的含義。
在這裡插入圖片描述

3.1.4.1 UGE(Urgent)

緊急的,這個欄位如果為1的時候,則緊急指標欄位才有效。表示當前的資料段中有緊急資料要優先傳送。

3.1.4.2 ACK(Acknowledgment)

確認標誌,當該欄位為1時,確認序號才有效。

3.1.4.3 PSH(Push)

因為接收方有快取區,當應用端發完一個完整的報文時候,不想讓接收方放在快取區,而是直接向上傳輸到應用層。

3.1.5.4 RST(Reset)

當該欄位為1的時候,表示兩端連線出現問題,必須斷開重新建立握手連線。

3.1.5.5 SYN(Synchronization)

該欄位為1表示要建立連線請求

  • SYN=1,ACK=0 表示傳送建立連線請求
  • SYN=1,ACK=1 表示確認建立請求,並且傳送一個建立請求(這個是表示兩個意思)

3.1.5.6 FIN(Finish)

該欄位為1的時候,表示要斷開連線。後面詳解4次揮手~

3.1.5.7 前3位

前3位一般為0,作為保留位。很多書籍上也將這3位劃分到保留位中,一共6位保留位。

可靠傳輸

TCP是如何實現可靠傳輸呢?在前面也說到了,既然要保證可靠傳輸,就是接收方,傳送方兩方一定要確保資料的最終狀態(不管是收到還是沒有收到),收到要給個應答,沒收到應答在一定時間內等待,結束之後重試,預設是沒有送達。所以可靠傳輸,一定是要對方收到傳送的資料。

ARQ(Automatic Repeat Request)

TCP開始使用ARQ停止等待協議來確保資料的送達。
傳送方傳送一段資料出去之後,一直等待著對方收到訊息,併傳送ACK確認訊息之後,才會傳送下一組資料。但是這其中分好多種情況。(圖來自網路)
1. 無差錯的情況

  • 傳送方傳送資料給接收方
  • 接收方收到資料,併傳送確認訊息
  • 依次上面的步驟,中間沒有差錯
    在這裡插入圖片描述

2. 確認丟失資料
就是傳送方傳送資料給接收方,這個包在傳輸過程中丟失了。
2.1 A傳送資料給B,B收到資料然後傳送ACK訊息,但是ACK訊息丟了

  • A 這個時候一直等待B的ACK訊息,但是一直沒等到(在自己設定的等待時間內),會重新傳送訊息給B
  • 這個時候B發現又收到了個同樣的訊息,這個時候A會丟掉這個訊息,再次回覆ACK給B

2.2 A傳送資料給B,這個資料就直接丟了,處理方式和上面2.1是一樣的,只不過A是第一次收到訊息~
在這裡插入圖片描述
3. 超時重傳
在A傳送訊息給B的時候,由於網路延遲的關係,A在傳送訊息出去之後,規定時間內沒收到B的ACK訊息,然後又重發了同樣的資料,這個時候B收到兩個一樣的資料,B的處理方式是直接丟掉重複的,只保留一個,然後回覆一個ACK。
在這裡插入圖片描述
問題

上述異常情況下(超時重傳,確認丟失)會一直重試?假如真的是一直有這種異常,難道無線死迴圈嗎?

解決:一般作業系統內部有個引數,重複傳了N次之後還是失敗,直接就傳送RST(Rest)訊息斷開TCP,需要重新建立連線了

總結
ARQ協議保證了資料能完整的傳送出去,但是這種一段一段的傳送資料效率很慢。為了解決這個問題,後來引進了聯絡ARQ協議。

連續ARQ+滑動視窗

ARQ協議解決了訊息能準確的傳送出去,並確認。但是這種一段一段效率比較慢。後來就演進了聯絡ARQ+滑動視窗來解決效率問題。
先看一張圖(來自百度網路)
在這裡插入圖片描述
視窗
在TCP建立連線的時候,接收方會返回一個視窗大小的欄位給到傳送方,就是用來告訴傳送方連續能傳送多少資料給到接收方。

  • 假設建立連線接收方告訴傳送方視窗大小10000位元組
  • 然後傳送端每次傳送資料段1000位元組
  • 那麼可以連續傳送10個資料段

連續ARQ協議+滑動視窗

  • ARQ協議還是上面所說的確認機制。
  • 連續ARQ是聯絡傳送過N條之後再確認一次。(如何確認後面介紹)
  • 然後視窗移動,再傳送接下來的一組資料。
    在這裡插入圖片描述

問題

如果接受方視窗能接收10個,但是傳送方只有兩個資料段傳送,還有8個傳送?服務端會一直等待著嗎?

答:接收方會等待接受第3個。如果超時了沒有收到第3個,則直接會確認。

SACK(選擇性確認)

由於連續ARQ協議+滑動視窗保證了資料快速傳送。但是這種理想狀況很好,但是連續傳送的過程中如果其中一個或多個丟了,也是要處理的。

使用限制
能否使用SACK取決於在建立連線的是,首部選項中有個SACK選項。
在這裡插入圖片描述

場景

  • 連續傳送了資料段1,2,3,4,5,6
  • 資料3,4丟失了

方式一

  • 接收方直接確認收到2
  • 傳送方這個時候就要重發後面的資料3,4,5,6
  • 這樣在連續資料傳送中,越前面的資料丟失,效率越低,因為後面的資料又要重傳。

方式二
由於第一種方式效率不咋地,所以應該升級,應該是誰丟了重發誰。

  • 這個時候藉助了TCP首部選項欄位,將要重新傳送的資料傳送到這裡。
  • Kind佔用一個位元組,值為5表示SACK選項
  • Length佔一個位元組。表明SACK一共有多少個位元組。
  • Left Edge:佔用4個位元組,左邊界
  • Right Edge:佔用4個位元組,右邊界
  • 所以一對邊界佔用8個位元組,TCP的首部選項部分佔用40個位元組
  • 所以最多確認訊息數量=(40-2)/8=4(組)
    在這裡插入圖片描述

問題

拆包是放在傳輸層還是網路層。
由於資料鏈路層MTU最大是1500位元組,所以網路層傳給鏈路層會進行拆包。那麼傳輸層超過1500位元組是要拆包還是網路層拆。

答:在傳輸層就應該拆包,因為本質區別就是需要保證資料傳輸可靠,所以就要TCP拆,要不然保證不了資料被網路層拆包之後能不能送達的問題。

流量控制

流量控制其實就是接收方要控制傳送方傳送資料的頻率以及大小。因為接收方有個快取區,用來接收資料的,如果滿了,還一直往裡面存,會導致資料丟失。所以接收方要控制傳送方傳送。

實現方式

上面有說到視窗欄位,其實還是通過確認視窗來動態限制傳送方傳送的速率。

  • 接收方發現快取區快滿了,就在接收到資料訊息的時候,在ACK段裡面調整視窗大小。
  • 因為傳送方傳送資料不能超過接收方視窗大小,從而限制了傳送資料大小和速率
  • 如果接收方給到的視窗大小是0的時候,傳送方會停止傳送資料
  • 如果視窗大小是0,如果不去解決,則如果接收方有空閒視窗能接收資料,則傳送方還在等待
  • 視窗為0傳送方會設定定時器,定時傳送個測試報文詢問接收方視窗大小,還為0,則重新整理定時器,否則直接傳送資料
    在這裡插入圖片描述

擁塞控制

上面說到的流量控制是接收方和傳送方之間的問題,是點對點的控制雙方接受資料能力。而擁塞控制則說的是通訊整條路上的資料擁塞情況,因為一個服務不只是針對於一個客戶端工作的,而且一條線路不只是為一個服務提供線路的。當某個服務大量佔用資源,導致別的服務流量不能到達。進而出現問題。

使用的方法

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

使用的欄位限制

  • MSS(Maximum Segment Size)資料段的最大長度,建立連線的時候確定
  • cwnd(congestion window)擁塞視窗
  • rwind(receive window)接收視窗
  • swind(send window)傳送視窗 =min(cwind, rwind)

慢開始(slow start)

擁塞避免(congestion avoidance)

快重傳(fast retransmit)

快恢復(fast recovery)

詳解TCP3次握手

其實如果認真閱讀了上面內容,其實三次握手是很容易理解的。還是一句話,需要訊息可靠到達,首先要建立可靠的通道,我能傳送給你,你能傳送給我。然後每次發訊息要確認收到。
在這裡插入圖片描述

  1. 客戶端主動向服務端傳送連線請求(可理解為我要申請一條給你傳送訊息的通道)這個訊息的標位:SYN=1,初始化序列號Seq=x(上面也講了序列號的作用)【SYN-SEND】狀態
  2. 服務端收到了SYN=1建立連線請求呀,服務端告訴客戶端行。所以要傳送一個確認訊號ACK=1,但是一般服務端,客戶端都是雙向通訊的,此時服務端也要想發資料給客戶端本來也要傳送一個SYN=1的訊號,所以為了減少一次通訊直接傳送[SYN=1,ACK=1,Seq=y,Ack=x+1]【SYN-RCVD】狀態
  3. 此時客戶端知道了,我可以和你發資料了,然後服務端也要和我建立連線。我就同意唄傳送[ACK=1,Syn=x+1,Ack=y+1]【ESTABLISHED狀態】

抓包分析
在這裡插入圖片描述

問題1:既然可以直接連線對方,傳送資料,為啥還要建立連線過程呢?

答:其實問這個問題,還是不瞭解TCP,其實不要連線是UDP的通訊過程,因為TCP要保證可靠的連線,所以不僅僅是說建立這麼簡單,裡面還有很多資訊,例如資料段最大長度MSS,視窗大小,能否進行SACK確認,序列號,縮放視窗係數等好多資訊,所以一般請求連線首部是32個位元組,肯定要大於最小的20個位元組。

問題2:建立連線為啥要三次,兩次不行嗎

答:其實這個還是為了確定性,如果省略了第三步,服務端也不知道我傳送的連線客戶端有沒有收到,而且是否讓我連線。如果認為收到了,並且可以連線,那麼真實情況是不讓連線,或者沒收到,伺服器一直會維護這個連線,佔用系統記憶體資源。所以TCP中好多定時器,如果不能給我確認,在定時器時間內重發。 多次失敗之後傳送RST訊號。重新建立連線

問題3:多次重試之後會進入死迴圈

答:回答第二個問題基礎上,如果有失敗步驟,會定時重發,為了不陷入死迴圈,在一定次數之後還是失敗,則傳送RST訊號,斷開連線重連。

詳解TCP4次揮手

當雙方通訊完成之後,就需要斷開連線。這裡斷開連線說的是,雙方都要自己斷開,客戶端覺得自己自己不需要傳送訊息了,就斷開傳送給服務端的通道。服務端如果也傳送完了,則也要傳送斷開請求。斷開請求可以隨便哪方主動發起,沒有先後順序。
在這裡插入圖片描述
流程

  1. 客戶端沒資料傳送,傳送斷開連線請求【FIN=1,ACK=1,Seq=u,Ack=v】然後自己進入了FIN-WAIT-1狀態。還能收資料
  2. 服務端同意你斷開連線【ACK=1,Seq=v,Ack=u+1】
  3. 客戶端此時收到了服務端確認,本來是直接進入關閉狀態【close】但是它也要等待服務端的關閉連線,所以進入了FIN-WAIT-2狀態
  4. 服務端發現自己也沒有訊息傳送給客戶端,也傳送一個【FIN】訊號給客戶端,進入last-ack階段
  5. 此時客戶端收到了服務端的FIN訊號,好了,我就可以等待關閉了進入【TIME-WAIT】,此時這個狀態會等待2倍MSL才會關閉。後面會將為啥2倍MSL
  6. 客戶端傳送ACK確認服務端可以斷開了,服務端進入關閉。
  7. 客戶端在TIME-WAIT時間到了之後, 也關閉。

問題1:為啥需要4次揮手

答:因為TCP是雙向通訊的,兩個通道,客戶端要關閉服務端,服務端也要關閉客戶端。所以一問一答就是4次。但是有的抓包情況是3次,原因是主動斷開連線的一方傳送了斷開連線請求,此時接收方發現自己也沒有資料傳送給它,也要傳送斷開,此時兩步可以合成一步來完成。

問題2:為啥主動斷開連線有個2MSL

  1. MSL(Maximun Segment LifeTime)資料段的最大生命週期,具體看作業系統如何實現,定義這個時間,一般2分鐘。
  2. 因為服務端(被動方)也傳送了關閉連線請求,所以我要不斷的去ACK確認,每次ACK都會重新整理這個時間。一旦在這個週期內沒有發現服務端再有FIN訊息,則表明它收到了ACK,關閉了連線。在等待完2MSL之後也會主動關閉。
  3. 因為一個資料段的生命週期是MSL,我要確保服務端傳送的訊息一定是被我接受到,所以我要等待,否則如果我立即斷開連線,服務端沒收到我的ACK,他會繼續傳送FIN訊號,如果此時又有一個程式正好建立了同樣客戶端的連線。那是不是剛上線就斷開了。所以取最壞情況的時間【ACK資訊和FIN資訊】2MSL
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章