計算機網絡原理——全網最易理解最全面的面試必考傳輸層TCP協議的十個重要特性及總結!!!

TCP報頭

先來分析分析每部分的含義和作用
在這裏插入圖片描述
源端口號/目的端口號:
表示數據從哪個進程來, 到哪個進程去.

32位序號/32位確認序號:
後面的圖中解釋

4位首部長度:
表示該tcp報頭有多少個4字節(32個bit),所以TCP頭部最大長度是15*4=60個字節

6位保留: 顧名思義, 先保留着, 以防萬一

6位標誌位
URG: 標識緊急指針是否有效
ACK: 標識確認序號是否有效
PSH: 用來提示接收端應用程序立刻將數據從tcp緩衝區讀走
RST: 要求重新建立連接. 我們把含有RST標識的報文稱爲復位報文段
SYN: 請求建立連接. 我們把含有SYN標識的報文稱爲同步報文段
FIN: 通知對端, 本端即將關閉. 我們把含有FIN標識的報文稱爲結束報文段

16位窗口大小: 看後圖

16位檢驗和:
由發送端填充, 檢驗形式有CRC校驗等. 如果接收端校驗不通過, 則認爲數據有問題. 此處的校驗和不光包含TCP首部, 也包含TCP數據部分.

16位緊急指針:
用來標識哪部分數據是緊急數據.
選項和數據暫時忽略

1、確認應答(ACK機制,可靠傳輸的最核心機制)

確認應答其實就跟我們平時打電話一樣,比如韋德今天要約詹姆斯去打球,韋德打電話給詹姆斯,然後詹姆斯回覆,詹姆斯的每次回覆就是一次確認應答。
在這裏插入圖片描述
對上述過程有個大致瞭解後我們再來看看我們TCP協議
在這裏插入圖片描述

2、 超時重傳

確認應答是比較理想的情況.數據在真實情況中傳輸過程中,可能會丟包的。
舉個例子
在這裏插入圖片描述
實際的傳輸
在這裏插入圖片描述
超時的時間如何確定?
最理想的情況下, 找到一個最小的時間, 保證 「確認應答一定能在這個時間內返回」.
但是這個時間的長短, 隨着網絡環境的不同, 是有差異的.
如果超時時間設的太長, 會影響整體的重傳效率;
如果超時時間設的太短, 有可能會頻繁發送重複的包;

TCP爲了保證無論在任何環境下都能比較高性能的通信, 因此會動態計算這個最大超時時間.
Linux中(BSD Unix和Windows也是如此), 超時以500ms(可以修改內核參數進行改變)爲一個單位進行控制, 每次判定超時重發的超時時 間都是500ms的整數倍.
如果重發一次之後, 仍然得不到應答, 等待 2*500ms 後再進行重傳.
如果仍然得不到應答, 等待 4 * 500ms 進行重傳.
依次類推, 以指數形式遞增累計到一定的重傳次數, TCP認爲網絡或者對端主機出現異常, 強制關閉連接.

3、連接管理機制

在正常情況下, TCP要經過三次握手建立連接, 四次揮手斷開連接

三次握手

三次握手是爲了建立連接
1.驗證通信雙方發送能力和接收能力是否正常.
2.通信雙方要協商一些重要參數.

第一次:
客戶端 - - > 服務器 此時服務器知道了客戶端要建立連接了
第二次:
客戶端 < - - 服務器 此時客戶端知道服務器收到連接請求了
第三次:
客戶端 - - > 服務器 此時服務器知道客戶端收到了自己的迴應

到這裏, 就可以認爲客戶端與服務器已經建立了連接.
下面就還是用之前的例子進行解釋
在這裏插入圖片描述
下面展示主機中真實的三次握手的詳情
在這裏插入圖片描述

爲什麼不用兩次?

在這裏插入圖片描述
不行.如果沒有最後一個ACK,此時主機B是無法知道自己的發送能力和對方的接受能力是否正常.

主要是爲了防止已經失效的連接請求報文突然又傳送到了服務器,從而產生錯誤。
如果使用的是兩次握手建立連接,假設有這樣一種場景,客戶端發送的第一個請求連接並且沒有丟失,只是因爲在網絡中滯留的時間太長了,由於TCP的客戶端遲遲沒有收到確認報文,以爲服務器沒有收到,此時重新向服務器發送這條報文,此後客戶端和服務器經過兩次握手完成連接,傳輸數據,然後關閉連接。此時之前滯留的那一次請求連接,因爲網絡通暢了, 到達了服務器,這個報文本該是失效的,但是,兩次握手的機制將會讓客戶端和服務器再次建立連接,這將導致不必要的錯誤和資源的浪費。
如果採用的是三次握手,就算是那一次失效的報文傳送過來了,服務端接受到了那條失效報文並且回覆了確認報文,但是客戶端不會再次發出確認。由於服務器收不到確認,就知道客戶端並沒有請求連接。

爲什麼不用四次?

在這裏插入圖片描述
因爲三次已經可以滿足需要了, 四次就多餘了,四次可以建立連接但是沒必要,就是將三次的第二次分成兩步就會需要傳輸兩個包,這樣效率就會低下。
在這裏插入圖片描述

四次揮手

四次揮手其實跟我們日常的情侶分手一樣
在這裏插入圖片描述

四次揮手只有在「延時應答」這種特殊情況的時候纔會有合併。
在這裏插入圖片描述
FIN是內核的事情.內核收到FIN就知道對方不會再繼續發送數據了.
主機B的應用程序就會繼續讀取接受緩衝區中積壓的數據,如果數據讀完了,繼續再讀,就會觸發異常. (異常相當於是從一個已經關閉連接的連接中讀取數據,數據讀完了才觸發的)

丟包分析
在這裏插入圖片描述
在這裏插入圖片描述

4、滑動窗口

沒有滑動窗口

傳輸過程,發一個收到一個,是串行過程,每次傳輸數據都要對應一個等待時間
傳輸N份數據就要等待N次應答時間
總的傳輸時間=N份數據傳輸時間+N份應答傳輸時間
在這裏插入圖片描述

帶滑動窗口

滑動窗口是發送方的概念.接收方只有一一個接受緩衝區,沒有"滑動窗口大小"這樣的概念.
發送方的窗口大小太大,是可能導致問題的.但是這個事情不是由連接管理協商出來的而是靠擁塞控制+流量控制確定的

像上述一發一收的方式性能較低,那麼我們一次發送多條數據,就可以大大的提高性能 (其實本質是將多個段的等待時間重疊在一起了)
滑動窗口是批量傳輸數據
總的傳輸時間=N份數據傳輸時間重疊成了1份時間,N份應答傳輸時間,重疊成了一份時間
在這裏插入圖片描述
每個窗口具體是怎麼滑動工作的呢?
窗口只有一個,是一格一格往後滑的,每當數據進入到窗口裏面就立刻被髮送了
窗口:不等待ACK的情況下,批量發送的最大數據量,就叫「窗口大小"
滑動:窗口範圍就是表示當前哪些數據在等待ACK,隨着一個ACK到達就立刻發送下一個數據,等待的數據包的範圍就在逐漸滑動

在這裏插入圖片描述

滑動窗口下三種丟包情況

1、數據包抵達,ACK丟了
在這裏插入圖片描述
比如上圖的窗口大小就是6000,如果主機B一直收不到1001的ACK所以窗口就一直不動等待最後一個數據的ACK,直到最後收到了6001的ACK,窗口就會默認之前的數據都已經收到,然後發送方就會立刻傳輸6001-12001的數據,這就相當於一下子就往後話滑了好幾步。
我們上面展示的是1-6000,就算最後6001這個數據的ACK丟了,那6001後面還有其他的數據可以參考,即使到了最後一個數據發完了,還有一個FIN作爲接收響應

2、數據包丟了/主機B接收順序反了
如果一直髮送不出去,就會超時連接,重置連接。

如果數據包丟了就會進行重傳,此處重傳只是重傳丟了的數據,其他數據不需要額外重傳這種叫做"快速重傳" (搭配滑動窗口下的超時重傳)
在這裏插入圖片描述
如果中間兩次丟包

滑動窗口是發送方的概念,接受緩衝區就是一一個固定大小的內存空間(空間大小是固定,可以通過內核的參數配置)如果接受緩衝區滿了就不會繼續傳輸了(流量控制機制)
在這裏插入圖片描述
如果是主機接收順序反了,後發先至
在這裏插入圖片描述
擁塞控制和流量控制共同決定發送方的窗口大小的.

5、擁塞控制

擁塞控制是考慮網絡傳輸路徑上的擁堵程度,互聯網類似一個交通網,可能某個環節就會擁堵。

就算接收方處理能力很強,但是如果傳輸路徑.上擁堵了,此時發送方發的快也沒用,接收方的處理能力,是好衡量. (接受緩衝區空餘空間大小)但是傳輸路徑太複雜,不好衡量。

擁塞控制由於不好衡量傳輸路徑的擁堵情況只能通過"反覆試探"的方式,逐漸試探出應該用多大的窗口大小。

在這裏插入圖片描述

爲啥要動態變化?
網絡的擁堵情況也是瞬息萬變的.要隨時根據網絡的實際情況進行動態調整.
爲啥曲線設定成這樣,都是從數學角度求出的一個最優解

6、流量控制

窗口大小不能無限大,如果窗口過大,傳輸的速率快,那樣接收方就可能處理不過來,接收方收到數據後是需要一定的時間處理的。

流量控制就是根據接收方的處理能力(通過接收緩衝區的「剩餘空間大小」來決定發送方的速率)來反向制衡發送方的發送速率(窗口大小)
在這裏插入圖片描述
流量控制可以用生產者消費者模型
在這裏插入圖片描述

在這裏插入圖片描述
如果中間有缺漏
在這裏插入圖片描述

流量控制總結

流量控制本質上,是根據接收方的處理能力來制約發送方的發送速率,根據接受緩衝區的剩餘空間大小,來制約發送方的滑動窗口大小,通過TCP報頭中的"窗口大小字段"來反映給發送方的。流量控制會影響到發送方的窗口大小,但是不是決定因素

可以通過生產者消費者模型理解,發送方是生產者,接收方的應用程序是消費者.
滑動窗口大小就和消費者應用程序的消費速度也是有關係的,如果剩餘空間大,說明消費速度就挺快的,發送速率就可以高一些,反之就發送速率低一些就行了.
如果窗口大小爲0,發送方會暫停發送,但是會定時發送一個探測報文. 如果發送方有空間了,就會立刻繼續傳輸.

7、延遲應答

是爲了提高效率,在流量控制的基礎上,儘量返回一個合理但是又比較大的窗口
在這裏插入圖片描述
延時應答其實就是讓ACK的發送時間晚一會(不影響可靠性的前提下)延時的時間中就會給應用程序提供更多的消費數據的機會,此時時間到了,再發ACK的時候,得到的窗口大小(接受緩衝區的剩餘空間就會更大)

所有的包都可以延遲應答嗎?

不是,
數量限制,每隔N個包就會應答一次
時間限制,超過最大延遲時間就應答一次

具體的數量和超時時間, 依操作系統不同也有差異; 一般N取2, 超時時間取200ms(這個延時應答的等待時間不能超過超時重傳的時間.

8、捎帶應答

在延遲應答的基礎上,爲進一步提高效率引入的機制
在這裏插入圖片描述

9、面向字節流的粘包問題

標題是面向字節流的粘包問題 所以只要涉及到字節流都會有可能發生這個問題

首先要明確, 粘包問題中的 「包」 , 是指的應用層的數據包.
在TCP的協議頭中, 沒有如同UDP一樣的 「報文長度」 這樣的字段, 但是有一個序號這樣的字段.
在這裏插入圖片描述
站在傳輸層的角度, TCP是一個一個報文過來的. 按照序號排好序放在緩衝區中.
站在應用層的角度, 看到的只是一串連續的字節數據.
那麼應用程序看到了這麼一連串的字節數據, 就不知道從哪個部分開始到哪個部分 是一個完整的應用層數據包
所以粘包,粘的是應用層的數據報 就是導致處理數據的時候 容易讀取半個應用層數據報的情況

那麼如何避免粘包問題呢?

明確兩個包之間的邊界
對於定長的包, 保證每次都按固定大小讀取即可;
對於變長的包, 可以在包頭的位置, 約定一個包總長度的字段, 從而就知道了包的結束位置;
對於變長的包, 還可以在包和包之間使用明確的分隔符(應用層協議, 是程序猿自己來定的, 只要保證分隔符不和正文衝突即可)
在這裏插入圖片描述

對於UDP協議來說, 是否也存在 「粘包問題」 呢?

UDP協議是沒這個問題的
TCP協議本身不幫你區分應用層數據報. (以字節爲單位傳輸)
UDP協議沒這個問題. (以UDP包爲單位)
因爲站在應用層的角度, 使用UDP的時候, 要麼收到完整的UDP報文, 要麼不收. 不會出現"半個"的情況

10、保活機制

在一些"異常情況"下,TCP對於連接會有特殊的處理。

進程奔潰

這種情況下 TCP連接會正常進行四次揮手端來連接(主要是進程退出 都會自動關閉相關的文件)

主機關機(按流程)

這個按流程就是用戶一步一步合理關機
在關機的時候會強制殺死進程 殺進程的時候會進行四次揮手斷開連接

主機斷電/斷網

接收方斷電

當接收方斷電 發送方發送消息的時候就會出現沒有ACK的情況 =>超時重傳 => 重傳一定的次數 => 重置連接 => 放棄對方然後斷開連接

發送方斷電

對於接收方來說本來也不知道發送方啥時候發送消息那接收方會一直等下去嗎?
肯定不會 其實在TCP中 互相會時不時給對方發送心跳包(一個毫無意義的數據報 只是證明對方還在線 還活着) 所以一旦一段時間都沒有收到對方的心跳包 就可以認爲對方已經掛了 就會斷開連接

心跳包

在這裏插入圖片描述

TCP可靠性的保證機制總結

TCP保證可靠性主要依靠下面7種機制:
1、檢驗和
TCP檢驗和的計算與UDP一樣,在計算時要加上12byte的僞首部,檢驗範圍包括TCP首部及數據部分,但是UDP的檢驗和字段爲可選的,而TCP中是必須有的。計算方法爲:在發送方將整個報文段分爲多個16位的段,然後將所有段進行反碼相加,將結果存放在檢驗和字段中,接收方用相同的方法進行計算,如最終結果爲檢驗字段所有位是全1則正確(UDP中爲0是正確),否則存在錯誤。
2、序列號
TCP將每個字節的數據都進行了編號,這就是序列號。
序列號的作用:
a、保證可靠性(當接收到的數據總少了某個序號的數據時,能馬上知道)
b、保證數據的按序到達
c、提高效率,可實現多次發送,一次確認
d、去除重複數據
數據傳輸過程中的確認應答處理、重發控制以及重複控制等功能都可以通過序列號來實現
3、確認應答機制(ACK)
TCP通過確認應答機制實現可靠的數據傳輸。在TCP的首部中有一個標誌位——ACK,此標誌位表示確認號是否有效。接收方對於按序到達的數據會進行確認,當標誌位ACK=1時確認首部的確認字段有效。進行確認時,確認字段值表示這個值之前的數據都已經按序到達了。而發送方如果收到了已發送的數據的確認報文,則繼續傳輸下一部分數據;而如果等待了一定時間還沒有收到確認報文就會啓動重傳機制。
4、超時重傳機制
當報文發出後在一定的時間內未收到接收方的確認,發送方就會進行重傳(通常是在發出報文段後設定一個鬧鐘,到點了還沒有收到應答則進行重傳)
5、連接管理機制
連接管理機制即TCP建立連接時的三次握手和斷開連接時的四次揮手。
6、流量控制
接收端處理數據的速度是有限的,如果發送方發送數據的速度過快,導致接收端的緩衝區滿,而發送方繼續發送,就會造成丟包,繼而引起丟包重傳等一系列連鎖反應。

TCP圖解

在這裏插入圖片描述

TCP與 UDP的對比

1、TCP適用於處理要求可靠性強的地方 效率自然不是很好
2、UDP適用於處理可靠性要求沒那麼高 但是要求效率高的地方(機房內部通信(分佈式系統)
如果兩個主機在同一個機房內部,兩個主機間的網絡環境就很簡單.此時丟包概率就較小考慮UDP)
3、UDP 能實現廣播 (一個人可以發給很多人信息),TCP只能一對一傳輸 (如果TCP想實現廣播就需要應用層配合 而且延遲較高)
4、什麼場景UDP和TCP都不能勝任?
遊戲方面 不僅要求可靠 而且要求效率極高(就好比我打遊戲 延遲100ms就很難受了)
這裏就需要引進一些其他基於TCP改進的傳輸層協議 比如 quic enet kcp udt
其實這些協議都是在想辦法擴大窗戶口 減少ACK的應答時間 縮短超時重傳的時間 提高擁塞控制的慢啓動 等等

如何基於UDP實現可靠傳輸

UDP本身是改變不了的(因爲是內核實現的) 也就是說只能在應用層實現UDP的可靠性
主要倆點 一是確認應答,二是超時重傳 (設置序列號和確認序號 設定接收緩衝區和發送緩衝區) 連接管理不是必須要 但是加上這倆個必然會降低效率 那麼就必須引進滑動窗口 萬一滑動太快就需要流量控制和擁塞控制 如果進一步提高效率的話就需要延遲應答和捎帶應答其實本質就是在應用層實現一些TCP的特點