TCP/IP協議的經典面試知識點總結
阿新 • • 發佈:2021-03-26
## 前言
大家好啊,我是湯小圓。
今天給大家推薦的是,TCP/IP協議的經典面試知識點總結,希望對大家有幫助,謝謝。
## 簡介
我們平時經常聽到的`TCP/IP`協議,其實是一個**協議族**;
只不過因為TCP、IP是其中最核心的協議,所以平時統稱為**TCP/IP協議**;
這個協議族裡面還有其他協議,比如`HTTP`、`FTP`、`SMTP`等;
## TCP分層框架
下圖是TCP/IP協議族的一個分層框架圖,從上往下依次是**應用層、傳輸層、網路層、鏈路層、物理層**
![](https://img2020.cnblogs.com/blog/2315950/202103/2315950-20210325213213706-856358804.png)
> 假如我想在機器A上,傳送一條"Hello World"到機器B,這個通訊過程是個什麼樣子呢?
首先機器A的應用層將訊息內容"Hello World"打包,然後經由傳輸層加上雙方的埠號,網路層加上雙方的IP地址,鏈路層加上雙方的Mac地址,經過多個路由器和閘道器,最終到達機器B,然後機器B再反過來解析出訊息內容"Hello World"
簡化之後的路徑就是:**訊息實體+埠號+IP地址+Mac地址**,封裝傳送,收到訊息後,再反過來解包操作
下面我們從上往下,依次介紹各個分層的作用
### 應用層
**按照固定的協議格式打包、解包資料。**
比如SMTP協議,雖然不同公司的郵箱格式不盡相同,但是都可以解析對方發來的郵件內容,就是因為他們都遵循SMTP協議
### 傳輸層
**決定資料要傳輸到遠端機器的哪個程式(埠),同時要表明資料來自源機器的哪個程式(埠),實現埠之間的通訊。**
比如本地跑一個測試程式A,監聽的是8080埠;遠端跑的測試程式B,監聽的是8080埠;
那麼傳輸層就會把本機的8080埠和遠端的8080埠都加到資料包上;
這樣遠端機器解析資料時,就知道要把資料傳給哪個程式。
### 網路層
**指定雙方的IP地址,並進行路由的定址和轉發**
> 這裡要明白一點就是,遠端機器的IP地址不是一次跳轉就可以到達的,要通過路由器和閘道器的多次跳轉,才會到達
>
> 這個可以參考視訊[《TCP/IP協議 - B站 - 馬士兵》](https://www.bilibili.com/video/BV1mA411q7Ry?p=7)
### 鏈路層
**指定遠端機器的Mac地址(確保不會發錯地方),以及本機的Mac地址**
> 既然有了Mac地址來作為機器的唯一ID,為啥還要有網路層的IP地址呢?
原因有兩個
1. IP是會變化的,有可能今天你跟機器A在聊天,明天就變成機器B了,當然會亂掉了
2. 現在的電腦太多了,數以千萬計,從這麼多電腦中找出某一個Mac地址,效率很低;但是IP不一樣,IP是由網段劃分的,有點類似於郵編,這樣就可以分段定址,效率高很多
## TCP的三次握手,四次揮手
### 三次握手
三次握手就是建立連線的過程,示意圖如下所示
![](https://img2020.cnblogs.com/blog/2315950/202103/2315950-20210325213237618-1407406818.png)
我們來再把流程簡化一點,就是:機器A傳送**連線請求**到機器B -> 機器B收到後,確認併發送同步訊號 -> 機器A收到確認訊號後,再次傳送確認訊號到機器B
這裡面涉及到幾個關鍵詞,下面列出一一說明下
#### 標誌關鍵詞
1. SYN(Synchronize Sequence Numbers),同步訊號,表示打算建立連線時的一個訊號
2. ACK(Acknowledgement),資料確認訊號,表示是否確認收到資料
#### 狀態關鍵詞
1. LISTENING,監聽狀態,表示還沒開始建立連線,正在監聽等待連線的到來
2. SYN_SENT,SYN已傳送,表示SYN已經發送,但是成功不成功還不知道
3. SYN_RCVD,SYN已收到,表示收到SYN訊號,也已經給了應答,但是連線還沒建立
4. ESTABLISHED,連線建立,表示雙方已經建立了連線,可以開始相互通訊了
下面詳細說下三次握手的連線過程
1. 機器A傳送同步訊號SYN=1,請求建立連線,並附帶序列號seq=x (機器A定義)
2. 機器B收到連線請求(SYN=1),返回 同步訊號SYN=1 和 資料確認訊號ACK=1,並附帶序列號 seq = y(機器B自己定義),確認序列號 ack = x + 1(方便機器A校驗)
3. 機器A收到機器B的反饋後,繼續傳送 確認訊號 ACK=1,並附帶序列號 seq = x + 1,確認序列號 ack = y + 1
> 為什麼要三次?兩次行不行?
兩次也可以,就是會出現**髒連線**和**資訊不對等**問題。(開玩笑的,兩次當然不行了,出現這麼多問題,大家都不用通訊了,每天光顧著建立連線了)
> 什麼是資訊不對等?它是怎麼產生的呢?
**資訊不對等**說的是,雙方對於對方的資訊處理能力瞭解的不一致
對於機器A來說,它內部有四個跟報文收發能力有關的標誌(我傳送成功了嗎,我接收成功了嗎,對方傳送成功了嗎,對方接收成功了嗎)
那麼對於機器B來說,也應有這四個標誌
現在假設只有兩次握手,那麼當兩次握手完成後,機器A的四個標誌是都確認成功了,但是機器B心裡卻會有個兩個疑問???
疑問1:我傳送成功了嗎?
疑問2:對方接收成功了嗎?
這時就會產生資訊的不對等。
就好比兩個人用對講機交流,我聽到你的講話了,我也迴應了,但是你突然不理我了。那我就對自己的表達能力產生疑問了。。。
下面這個表格很形象的說明了 兩次握手導致資訊不對等的問題
![](https://img2020.cnblogs.com/blog/2315950/202103/2315950-20210325213258422-940355976.png)
> 什麼是髒連線?它又是怎麼產生的呢?
瞭解髒讀之前要先明白一個知識點,就是報文存活的時間 > 請求連線的超時時間(一般情況下)
現在假設我們用的是兩次握手,那麼**髒連線**就是**機器A有一次請求連線超時,然後請求重連,等到重連成功後,上一次超時的請求又來,此時這個請求對於機器B來說就是髒連線**
下面是產生兩次握手產生髒連線的示意圖
![](https://img2020.cnblogs.com/blog/2315950/202103/2315950-20210325213329788-239591703.png)
從圖中可以看到,重新發送的連線請求,兩次握手成功並斷開連線後,之前超時的請求又來了,此時機器B傳送第二次握手,連線建立;
但是因為此時客戶端的狀態是ESTABLISHED(已建立連線),而不是SYN_SENT(同步訊號已傳送),所以機器A不認這個連線,無法通訊,也就成了髒連線。
### 四次揮手
四次揮手就是斷開連線的過程,示意圖如下所示
![](https://img2020.cnblogs.com/blog/2315950/202103/2315950-20210325213335759-439687564.png)
這裡面涉及到幾個上面沒提到的關鍵詞,下面列出一一說明下
#### 標誌關鍵詞
1. FIN(Finish),完成訊號,表示通訊已經完成,接下來打算關閉連線了
#### 狀態關鍵詞
1. FIN_WAIT_1,傳送斷開連線後的等待狀態階段1,表示已經發送了 FIN 請求,但是對方還沒確認
2. FIN_WAIT_2,傳送斷開連線後的等待狀態階段2,表示對方 ACK 確認了,但是對方還沒傳送 FIN 請求
3. TIME_WAIT,固定時間等待期,表示對方已經發送了 FIN 請求 和 ACK 確認訊號,我也傳送了確認訊號 ACK ,過一會就可以關閉連線了
4. CLOSE_WAIT,關閉等待期,表示接收到 FIN 請求,併發送了 ACK 確認訊號,這邊開始準備斷開連線的收尾工作
5. LAST_ACK,最後確認,表示已經發送了 FIN 請求和 ACK 確認訊號,等待對方 ACK 確認就可以關閉了
6. CLOSED,關閉狀態,表示已經關閉連線
下面詳細說下四次揮手的斷開連線過程
1. 機器A傳送 FIN 訊號,請求關閉連線,並附帶序列號 seq = u
2. 機器B收到 FIN 訊號,返回 ACK 確認訊號,並開始準備斷開連線的收尾工作
3. 等到收尾完成,機器B再發送 FIN 訊號 和 ACK 確認訊號,並附帶序列號 seq = v, 確認序列號 ack = u + 1
4. 機器A收到後,進入 TIME_WAIT 期,併發送 ACK 確認訊號,附帶序列號 seq = u + 1,確認序列號 ack = v + 1
5. 機器B收到後,關閉連線
6. 機器A等待固定時間(2MSL,下面會介紹這個引數)後,也關閉連線
> 為什麼握手是三次,揮手卻要四次呢?
因為揮手多了一個清理現場的部分,就是傳送剩餘的資料,處理現場,關閉相關資源
其實如果沒有什麼可以清理的,機器B也可能省略這個階段,然後在收到機器A的 FIN 訊號時,直接返回 FIN 和 ACK 訊號,這樣就會變成三次揮手
> 2MSL是什麼引數?
這個 2MSL 就是報文在網路上的生存時長,意思就是報文如果在網路上存在的時間超過這個引數,那麼報文就會自動丟棄
這個數值如果過大,會造成資源的浪費
因為如果數值過大,好多連線就會卡在TIME_WAIT這裡,還佔著埠,那麼這個埠就啥也不幹了
所以一般建議這個數值調小一點(建議小於30S),尤其是在伺服器端
> 那TIME_WAIT 這個階段可以跳過嗎?為什麼要在這裡等待一段時間呢?
不可以,原因有二
1. 有可能機器A最後發完 ACK 確認訊號後,對方沒收到,此時機器A如果立馬斷開連線,就會導致報文丟失;
相反的,正因為有了這個階段,所以當對方沒收到ACK訊號時,對方過段時間會重發FIN+ACK訊號,此時機器A會重新發送ACK訊號,並重新計時
2. 防止失效請求,防止已失效連線的請求資料包和正常連線的請求資料包混淆而發生異常
已失效的連線,指的是握手過程中由於某些原因沒有成功,但是也沒斷開的連線
現在有了這個TIME_WAIT階段,那麼前面已失效的連線就會因為超時而被丟棄,從而不會干擾到正常的連線
## 總結
以上只是關於TCP/IP協議的簡單介紹,主要為了小白入門;
想深入細節的可以參考《TCP/IP 核心技術卷一》和馬士兵老師的B站視訊
**參考資料**:
1. 《碼出高效:Java開發手冊》
2. 《TCP/IP 核心技術卷一》
3. B站馬士兵視訊:https://www.bilibili.com/video/BV1mA411q7Ry?p=7
**圖片來源**:以上所有圖片均來自《碼出高效 Java開發手冊》
## 後記
最後,感謝大家的觀看,