面試題:TCP 和 UDP 區別是什么?TCP 連接為什么是三次握手而不是兩次或者四次?TIME_WAIT狀態存在的意義是什么?
一、面試官:什么是TCP的三次握手?三次握手的過程是怎么樣的?為什么需要三次握手而不是兩次或者四次?
TCP(傳輸控制協議)是一種面向連接的、可靠的傳輸層協議。在建立連接時,TCP使用三次握手(Three-way Handshake)機制來確保通信雙方能夠同步彼此的序列號,并確認雙方都具備發送和接收數據的能力 。
1. 三次握手的具體過程
(1) 第一次握手
客戶端向服務器發送一個SYN(同步)包,表示希望建立連接。這個SYN包中包含一個隨機生成的初始序列號(ISN, Initial Sequence Number),用于后續數據傳輸的編號。發送完成后,客戶端進入SYN_SENT狀態,等待服務器的響應 。
(2) 第二次握手
服務器收到客戶端的SYN包后,會向客戶端回復一個SYN+ACK包。其中,SYN表示服務器同意建立連接,ACK是對客戶端SYN包的確認,確認號為客戶端的初始序列號加1。同時,服務器也會生成自己的初始序列號,并將其包含在SYN包中。此時,服務器進入SYN_RCVD狀態 。
(3) 第三次握手
客戶端收到服務器的SYN+ACK包后,會再向服務器發送一個ACK包,作為對服務器SYN包的確認。這個ACK包的確認號是服務器的初始序列號加1。發送完成后,客戶端和服務器都進入ESTABLISHED狀態,連接正式建立,雙方可以開始傳輸數據 。
2. 為什么需要三次握手而非兩次或者四次?
(1) 同步雙方的初始序列號
TCP協議的通信雙方都必須維護一個序列號,這是確保可靠傳輸的關鍵因素。序列號在TCP連接中扮演了重要角色,它具有以下作用:
- 接收方可以消除重復的數據,確保數據的準確性。
- 接收方可以按照序列號的順序接收數據包,保證數據的完整性。
- 序列號可以標識已經被對方接收的數據包,實現可靠的數據傳輸。
因此,在建立TCP連接時,客戶端發送帶有初始序列號的SYN報文,并需要服務器回復一個ACK報文,表示成功接收了客戶端的SYN報文。然后,服務器發送帶有初始序列號的SYN報文給客戶端,并等待客戶端的應答,這樣一來一回,才能確保雙方的初始序列號能夠可靠地同步。
雖然四次握手也可以實現可靠地同步雙方的初始序列號,但由于第二步和第三步可以合并為一步,所以最終演變成了三次握手。而兩次握手只能保證一方的初始序列號被對方成功接收,無法保證雙方的初始序列號都能被確認接收。因此,三次握手是為了確保TCP連接的穩定性和可靠性而采取的最佳選擇。
(2) 防止舊的重復連接初始化造成混亂
在網絡通信中,數據包可能會因為網絡擁塞、路由問題或其他原因而延遲到達。這些延遲的數據包被稱為“歷史數據包”或“舊數據包”。如果TCP只使用兩次握手,服務器無法區分當前收到的SYN包是新的連接請求,還是一個延遲到達的舊連接請求 。
假設以下場景:
客戶端發送了一個SYN包(連接請求),但由于網絡延遲,這個SYN包沒有及時到達服務器。
客戶端由于超時未收到服務器的響應,重新發送了一個新的SYN包(新的連接請求)。
如果采用兩次握手,服務器收到新的SYN包后,回復SYN+ACK包,并認為連接已建立。
隨后,舊的SYN包延遲到達服務器。由于服務器只進行兩次握手,它會將這個舊的SYN包誤認為是一個新的連接請求,并回復SYN+ACK包,進而為這個不存在的連接分配資源 。
三次握手如何避免這個問題?在三次握手中:
- 當服務器收到SYN包后,會回復SYN+ACK包(第二次握手),但不會立即進入連接狀態。
- 只有當客戶端收到SYN+ACK包并回復ACK包(第三次握手)后,服務器才會確認這是一個有效的連接。
- 如果舊的SYN包延遲到達服務器,服務器會回復SYN+ACK包,但客戶端不會發送最終的ACK包,因為客戶端并沒有發起這個舊的連接請求。因此,服務器會丟棄這個無效的連接,避免資源浪費 。
(3) 確認雙方的收發能力
三次握手確保了雙方都能正常發送和接收數據。例如,客戶端通過第二次握手確認服務器能接收到自己的包;服務器通過第三次握手確認客戶端能接收到自己的包 。
二、面試官追問:第三次握手過程中,如果客戶端的ACK未送達服務器,會發生什么?如果已經建立了連接,但客戶端出現了故障怎么辦?
在TCP三次握手過程中,如果第三次握手的ACK包未送達服務器,會發生以下情況:
1. 服務器的行為
服務器在發送SYN+ACK包后,會進入SYN_RCVD狀態,并等待客戶端的ACK確認。
如果服務器沒有收到客戶端的ACK包,它會認為自己的SYN+ACK包可能丟失,因此會根據TCP的超時重傳機制,重新發送SYN+ACK包。
通常情況下,服務器會嘗試重傳SYN+ACK包最多5次(具體次數取決于實現),每次重傳的時間間隔會逐漸增加(例如3秒、6秒、12秒等)。
如果經過多次重傳后仍然沒有收到客戶端的ACK確認,服務器會放棄建立連接,并進入CLOSED狀態,釋放相關資源。
在服務端進入CLOSED狀態之后,如果客戶端向服務器發送數據,服務器會以RST包應答。
2. 客戶端的行為
客戶端在發送ACK包后,會進入ESTABLISHED狀態,認為連接已經建立。
如果客戶端隨后開始向服務器發送數據,而服務器尚未收到ACK確認,服務器在收到數據包時會檢查其中的ACK標志位。如果數據包中包含有效的ACK信息,服務器會將其視為對SYN+ACK的確認,并完成連接的建立。
3. 如果已經建立了連接,但客戶端出現了故障怎么辦?
在TCP協議中,若已建立連接但客戶端出現故障,服務器端會通過保活機制(Keepalive)檢測連接狀態,并采取相應措施釋放資源。以下是詳細分析:
(1) TCP連接故障處理機制
保活機制(Keepalive):
- 觸發條件:當連接長時間無數據交互時(默認2小時),服務器會啟動保活探測。
- 探測過程:服務器每隔75秒發送一次探測報文(空數據包),若連續10次(約11分鐘)未收到客戶端響應,則判定連接失效。
- 結果處理:服務器主動關閉連接,釋放占用的端口和內存資源,避免資源泄漏。
(2) 潛在問題與解決方案
保活機制缺陷:
檢測延遲:默認11分鐘的檢測周期較長,可能無法滿足實時性要求。
優化建議:在應用層實現心跳機制(如HTTP長輪詢、WebSocket),通過自定義協議定期發送心跳包,縮短故障檢測時間。
資源競爭風險:
場景:若客戶端崩潰前未釋放連接,服務器可能因資源耗盡(如TIME_WAIT狀態堆積)無法建立新連接。
優化建議:
- 調整內核參數(如`net.ipv4.tcp_keepalive_time`)縮短保活間隔。
- 使用連接池技術復用連接,減少頻繁建立/釋放的開銷。
三、面試官追問:TCP四次揮手的過程是怎么樣的?為什么不能把服務器發送的ACK和FIN合并起來,變成三次揮手?
TCP斷開連接需要通過四次揮手的方式。雙方都有能力主動斷開連接,一旦斷開連接,主機中的各種「資源」將被釋放。
TCP連接是全雙工的,因此每個方向都必須單獨進行關閉。首先進行關閉的一方將執行主動關閉,而另一方則執行被動關閉。
整個過程通常涉及四個步驟,每個步驟都通過交換TCP報文段來完成。而且每次揮手客戶端和服務端都會進入到相應的狀態 (FIN_WAIT_1、FIN_WAIT_2、CLOSED_WAIT、LAST_ACK 和 TIME_WAIT)。
1. 四次揮手詳細步驟
i
(1) 第一次揮手:主動關閉方發送FIN報文
- 過程:主動關閉方(通常是客戶端)發送一個FIN(Finish)報文段,表示它已經沒有數據要發送了,希望關閉連接,但此時主動關閉方還能接受數據。此時,主動關閉方進入FIN_WAIT_1狀態,等待被動關閉方的確認。
- 報文段內容:FIN報文段中,FIN標志位被設置為1,同時可能包含一個序列號(seq),用于標識該報文段在數據流中的位置。
(2) 第二次揮手:被動關閉方回應ACK報文
- 過程:被動關閉方(通常是服務器)收到FIN報文段后,發送一個ACK(Acknowledgment)報文段作為回應,表示已經收到了關閉請求。此時,被動關閉方進入CLOSE_WAIT狀態,表示它已經準備好關閉連接,但還可能需要處理剩余的數據。主動關閉方收到ACK報文段后,進入FIN_WAIT_2狀態。在這個階段,如果服務端處理好了數據(如果有的話)會將數據發送給客戶端。
- 報文段內容:ACK報文段中,ACK標志位被設置為1,確認序號(ack)為收到的FIN報文段的序列號加1,表示對FIN報文段的確認。
(3) 第三次揮手:被動關閉方發送FIN報文
- 過程:被動關閉方在處理完剩余數據后,發送一個FIN報文段,表示它也沒有數據要發送了,請求關閉連接。此時,被動關閉方進入LAST_ACK狀態,等待主動關閉方的確認。
- 報文段內容:FIN報文段中,FIN標志位被設置為1,同時可能包含一個序列號(seq),用于標識該報文段在數據流中的位置。
(4) 第四次揮手:主動關閉方回應ACK報文并進入TIME_WAIT狀態
- 過程:主動關閉方收到被動關閉方的FIN報文段后,發送一個ACK報文段作為回應,表示已經收到了關閉請求。此時,主動關閉方進入TIME_WAIT狀態,等待一段時間(通常為2MSL,即最大段生存期的兩倍),以確保被動關閉方收到了最終的ACK報文段。如果被動關閉方沒有收到ACK報文段,它會重新發送FIN報文段,主動關閉方則可以再次發送ACK報文段。等待時間結束后,主動關閉方進入CLOSED狀態,連接正式關閉。被動關閉方收到ACK報文段后,也立即進入CLOSED狀態。
- 報文段內容:ACK報文段中,ACK標志位被設置為1,確認序號(ack)為收到的FIN報文段的序列號加1,表示對FIN報文段的確認。
2. 為什么不能將ACK和FIN合并為三次揮手?
為了更好地理解為什么揮手需要四次,讓我們再來回顧一下雙方發出FIN包的過程。這樣我們就能理解為什么需要四次揮手了。
在關閉連接時,當客戶端向服務端發送FIN時,這僅僅表示客戶端不再發送數據了,但是它仍然可以接收數據。
當服務端收到客戶端的FIN報文時,它首先會回復一個ACK應答報文。然而,服務端可能還有數據需要處理和發送,所以它會等待直到它不再發送數據時,才會發送FIN報文給客戶端,表示同意現在關閉連接。
通過上述過程,我們可以看出,服務端通常需要等待完成數據的發送和處理,所以服務端的ACK和FIN通常會分開發送,這就導致了比三次握手多了一次揮手的過程。
四、面試官追問:為什么主動關閉方最后一次揮手后會進入TIME_WAIT狀態而不是直接釋放資源?為什 TIME_WAIT 狀態持續的時間是2MSL?
TIME_WAIT 狀態的存在是為了確保網絡連接的可靠關閉。只有主動發起關閉連接的一方(即主動關閉方)才會有 TIME_WAIT 狀態。
客戶端進入 TIME_WAIT 狀態是 TCP 協議可靠性和健壯性設計的重要體現,其核心意義體現在以下關鍵方面:
1. 確保可靠終止連接
避免數據丟失:在 TCP 四次揮手過程中,客戶端發送最后一個 ACK 確認報文后進入 TIME_WAIT 狀態,等待 2 倍最大報文段生存時間(2MSL)。若該 ACK 丟失,服務端會重傳 FIN 報文,客戶端可在 TIME_WAIT 期間重新發送 ACK,確保服務端正確關閉連接。
處理延遲或重傳報文:網絡中可能存在延遲或重傳的報文,TIME_WAIT 狀態確保這些報文在連接完全終止前被丟棄,避免干擾后續新連接。
2. 防止連接復用沖突
避免端口和地址混淆:TCP 連接由四元組(源 IP、源端口、目的 IP、目的端口)唯一標識。TIME_WAIT 狀態確保在舊連接完全終止前,相同的四元組不會被新連接復用。若新連接復用舊連接的地址和端口,舊連接的延遲報文可能被誤認為新連接的數據,導致數據混亂。
維持連接唯一性:通過等待 2MSL,TIME_WAIT 狀態確保舊連接的報文在網絡中自然消失,從而保證新連接的獨立性和正確性。
為什 TIME_WAIT 狀態持續的時間是2MSL?
MSL是報文在網絡中存活的最長時間,超過該時間后,報文將被丟棄。不同操作系統或網絡設備對MSL的定義可能存在差異(如RFC 793建議MSL為2分鐘,但實際可能更短)。
如上所述,TCP報文在網絡中可能因延遲、路由重傳等原因滯留,最長可達MSL時間。若主動關閉方在TIME_WAIT階段未等待足夠時間,新建立的連接可能復用相同的四元組(源IP、源端口、目的IP、目的端口),導致滯留的舊連接報文被誤認為新連接數據,引發數據混亂或協議錯誤。
等待2MSL可確保所有舊連接報文因超時而被丟棄,避免對新連接造成干擾。例如,若MSL為30秒,則2MSL為60秒,足以覆蓋網絡中可能的最長滯留時間。
雖然TIME_WAIT狀態會占用端口和系統資源,但2MSL的等待時間是協議可靠性的必要代價。在高并發場景下,可通過調整系統參數(如縮短TIME_WAIT時間或復用TIME_WAIT連接)優化資源利用率,但需謹慎權衡可靠性與性能。
五、面試官追問:TCP和UDP協議的區別是什么?它們的適用場景分別有哪些?
TCP是一種面向連接、可靠的、基于字節流的傳輸層通信協議。
面向連接:面向連接意味著TCP通信是一對一的,即點對點端到端的通信,不像UDP可以同時向多個主機發送消息,因此無法實現一對多的通信。
可靠的:TCP的可靠性保證了無論網絡鏈路中發生何種變化,TCP都能確保報文的可靠傳輸到達接收端,這也使得TCP的協議報文格式相比UDP更為復雜。
基于字節流:基于字節流的特性使得TCP可以傳輸任意大小的消息,而且保證了消息的有序性,前一個消息未被完全接收,即使后面的字節已經接收,TCP也不會將其交付給應用層處理。同時對于重復的報文會自動丟棄。
UDP(User Datagram Protocol)是一種面向無連接的通信協議,相比于TCP,UDP不提供復雜的控制機制。UDP協議允許應用程序在不建立連接的情況下直接發送封裝的IP數據包。開發人員選擇使用UDP而不是TCP時,應用程序與IP直接進行通信。
1. 核心特性對比
特性 | TCP(面向連接) | UDP(無連接) |
連接模式 | 建立虛擬連接(三次握手) | 無連接,獨立發送數據包 |
可靠性 | 保證數據按序、無丟失、無重復 | 不保證數據可靠性(可能丟包、亂序、重復) |
流量控制 | 滑動窗口機制(動態調整發送速率) | 無流量控制,發送方不感知接收方狀態 |
擁塞控制 | 慢啟動、擁塞避免、快速重傳等算法 | 無擁塞控制,發送速率由應用層決定 |
數據包順序 | 嚴格保證順序(通過序列號排序) | 不保證順序,需應用層自行處理 |
頭部開銷 | 20字節(基礎)+可選選項(如時間戳) | 8字節(固定) |
典型應用場景 | 文件傳輸、網頁瀏覽、遠程登錄等 | 實時視頻、在線游戲、DNS查詢、物聯網等 |
2. 關鍵差異解析
(1) 可靠性 vs 高效性
- TCP:通過確認機制(ACK)、重傳(Retransmission)、序列號(Sequence Number)等技術確保數據可靠傳輸,但會增加延遲和開銷。
- UDP:僅提供“盡力而為”的傳輸,不保證數據完整性,但因無需等待確認,可實現更低延遲的實時通信。
(2) 連接建立 vs 即發即走
- TCP:需通過三次握手建立連接(SYN→SYN+ACK→ACK),類似打電話前先撥號確認;關閉時需四次揮手(FIN→ACK→FIN→ACK),類似掛電話前的禮貌道別。
- UDP:直接發送數據包,無需任何連接建立過程,類似寫信無需確認收件人是否在線。
(3) 性能開銷對比
- TCP:頭部包含序列號、確認號、窗口大小等字段,共20字節基礎開銷,復雜場景可能擴展至60字節。
- UDP:頭部僅包含源端口、目的端口、長度、校驗和等8字節字段,開銷極低。
3. 典型應用場景
(1) TCP適用場景
- 需要高可靠性的應用:如HTTP/HTTPS(網頁)、FTP(文件傳輸)、SMTP(郵件)、SSH(遠程登錄)。
- 數據完整性敏感的場景:如銀行交易、數據庫同步。
(2) UDP適用場景
- 實時性要求高的應用:如視頻直播(允許少量丟包)、在線游戲(低延遲比丟包更重要)。
- 廣播/組播通信:如視頻會議、物聯網設備群控。
- 簡單請求-響應模式:如DNS查詢(通常單包即可完成)。
- 自定義協議設計:如QUIC協議(Google基于UDP開發,融合TCP可靠性)。
4. 優缺點總結
協議 | 優點 | 缺點 |
TCP | - 可靠性高 | - 延遲高(三次握手+四次揮手) |
UDP | - 延遲低 | - 無可靠性保障 |
總結:TCP與UDP的選擇本質是“可靠性”與“效率”的權衡。TCP適用于對數據完整性要求嚴苛的場景,而UDP更適合實時性優先或簡單通信需求的場景。實際開發中,可根據業務特性選擇協議,或通過混合方案兼顧兩者優勢。