TCP 協議是我們每天都在使用的一個網絡通訊協議,因為絕大部分的網絡連接都是建立在 TCP 協議上的,比如你此刻正在看的這篇文章是建立在 HTTP(Hypertext Transfer Protocol,超文本傳送協議) 應用層協議的基礎上的,而 HTTP 協議的“底層”則是建立在 TCP 的傳輸層協議上的。因此可以理解為,你之所以能看到本篇文章就是得益于 TCP 協議的功勞。
我們本課時講的是,說一下 TCP 三次握手的執行流程,以及為什么需要三次握手?
典型回答
在回答這個問題之前,首先我們需要搞清楚兩個概念,第一,什么是 TCP?第二,什么是 TCP 連接?只有搞明白了這兩個問題,我們才能徹底搞懂為什么 TCP 需要三次握手?
什么是 TCP?
首先來說 TCP(Transmission Control Protocol,傳輸控制協議)是一個面向連接的、可靠的、基于字節流的傳輸層協議。從它的概念中我們可以看出 TCP 的三個特點:面向連接、可靠性和面向字節流。
TCP 的特點
面向連接:是指 TCP 是面向客戶端和服務器端連接的通訊協議,使用它可以將客戶端和服務器端進行連接。
可靠性:是指無論網絡環境多差,TCP 都可以保證信息一定能夠傳遞到接收端。
TCP 之所以可以保證可靠性主要得益于兩個方面,一個是“狀態性”,另一個是“可控制性”。所謂狀態性是指 TCP 會記錄信息的發送狀態,例如,哪些數據收到了、哪些數據沒收到等狀態信息都會被記錄;可控制性是指 TCP 會根據狀態情況控制自己的行為,比如當 TCP 意識到丟包了就會控制重發此包,這樣就實現了 TCP 的可靠性。
面向字節流:是指 TCP 是以字節流的方式進行數據傳輸的。
RFC 793 對 TCP 連接的定義如下:
Connections: The reliability and flow control mechanisms described above require that TCPs initialize and maintain certain status information for each data stream. The combination of this information, including sockets, sequence numbers, and window sizes, is called a connection.
小貼士: TCP 之所以被廣泛應用,首先是因為它是一個標準化的協議,TCP 的標準協議就是由 RFC 793 定義的,它已經有了 30 多年的歷史,并且已經被多次更新。RFC(Request For Comments)是 IETF(Inte.NET Engineering Task Force)的正式文檔。IETF 是一家制定互聯網標準的組織,它制定了 Internet(互聯網)的整體協議體系,凡是經過 IETF 評審認可的標準都會被發布為帶編號的 RFC 的文檔。
TCP 定義的大致意思是,用于保證可靠性和流控制機制的信息,包括 Socket、序列號及窗口大小被稱為連接。
其中,Socket 是由 IP 地址加端口號組成的,序列號是用來解決亂序問題的,而窗口大小則是用來做流量控制的。
TCP 三次握手的執行流程
接下來我們來看 TCP 三次握手的執行流程,如下圖所示:
關鍵字說明:
- SYN(SYNchronize Sequence Numbers),同步序列編號;
- ACK(Acknowledge Character),確認字符;
- SEQ(Sequence Number),序列號。
TCP 的執行流程如下:
- 最開始時客戶端和服務端都處于 CLOSED 狀態,然后服務端先主動監聽某個端口,此時服務器端就變成了 LISTEN(監聽)狀態;
- 然后客戶端主動發起連接,發送 SYN(同步序列編號),此時客戶端就變成了 SYN-SENT 狀態;
- 服務端接收到信息之后返回 SYN 和 ACK 至客戶端,此時服務器端就變成了 SYN-REVD 狀態;
客戶端接收到消息之后,再發送 ACK 至服務器端,此時客戶端就變成了 ESTABLISHED(已確認)狀態,服務端收到 ACK 之后,也變成了 ESTABLISHED 狀態,此時連接工作就執行完了。
為什么 TCP 需要三次握手?
了解了以上 TCP 的基礎概念之后,我們再來看一下 TCP 為什么需要三次握手?
原因一:防止重復連接
首先來說 RFC 793 - Transmission Control Protocol 其實就指出了三次握手的主要原因,它的描述如下:
The principle reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion.
翻譯為中文的意思是,三次握手的主要原因是為了防止舊的重復連接引起連接混亂問題。
比如在網絡狀況比較復雜或者網絡狀況比較差的情況下,發送方可能會連續發送多次建立連接的請求。如果 TCP 握手的次數只有兩次,那么接收方只能選擇接受請求或者拒絕接受請求,但它并不清楚這次的請求是正常的請求,還是由于網絡環境問題而導致的過期請求,如果是過期請求的話就會造成錯誤的連接。
所以如果 TCP 是三次握手的話,那么客戶端在接收到服務器端 SEQ+1 的消息之后,就可以判斷當前的連接是否為歷史連接,如果判斷為歷史連接的話就會發送終止報文(RST)給服務器端終止連接;如果判斷當前連接不是歷史連接的話就會發送指令給服務器端來建立連接。
原因二:同步初始化序列化
通過上面的概念我們知道 TCP 的一個重要特征就是可靠性,而 TCP 為了保證在不穩定的網絡環境中構建一個穩定的數據連接,它就需要一個“序列號”字段來保證自己的穩定性,而這個序列號的作用就是防止數據包重復發送,以及有效的解決數據包接收時順序顛倒的問題。
那么在建立 TCP 連接時就需要同步初始化一個序列號來保證 TCP 的穩定性,因此它需要執行以下過程:
- 首先客戶端發送一個攜帶了初始序列號的 SYN 報文給服務器端;
- 服務端接收到消息之后會回復一個 ACK 的應答報文,表示客戶端的 SYN 報文已被服務端成功接收了;
- 而客戶端收到消息之后也會發送一個 ACK 給服務端,服務器端拿到這個消息之后,我們就可以得到一個可靠的初始化序列號了。
而如果是兩次握手的話,就無法進行序列號的確認工作了,因此也就無法得到一個可靠的序列號了,所以 TCP 連接至少需要三次握手。
以上兩種原因就是 TCP 連接為什么需要三次握手的主要原因,當然 TCP 連接還可以四次握手,甚至是五次握手,也能實現 TCP 連接的穩定性,但三次握手是最節省資源的連接方式,因此 TCP 連接應該為三次握手。
考點分析
TCP 知識是計算機編程基礎,也是面試中常見的面試問題,因為我們現在所使用的大部分連接都是建立在 TCP 基礎上的。因此對 TCP 的掌握可以讓我們更清楚地理解技術的實現過程,也能幫我們寫出更加優秀的代碼,以及排查一些和網絡相關的問題。
和此知識點相關的面試題還有以下這些:
- 什么是 UDP?
- TCP 和 UDP 有什么區別?
UDP(User Data Protocol,用戶數據報協議)是無連接的、簡單的、面向數據報的傳輸層協議。也就是 UDP 在發送數據之前,無須建立客戶端與服務端的連接,直接發送消息即可。
UDP 的協議頭有 8 個字節(64 位),如下圖所示:
其中源端口和目標端口是指記錄發送方和接收方端口;UDP 包長度是指 UDP 頭部加上 UDP 數據的總長度;UDP 校驗和用于效驗 UDP 的內容是否可靠。
UDP 常見的使用場景有:語音、視頻等多媒體通信、DNS(域名轉化)、TFTP 等。
TCP VS UDP
TCP 和 UDP 的區別主要體現在以下 7 個方面:
- 可靠性,TCP 有“狀態性”和“可控制性”可以保證消息不重復、按順序、不丟失的發送和接收,而 UDP 則不能保證消息的可靠性;
- 連接,TCP 是面向連接的傳輸層協議,傳輸數據前先要建立連接,而 UDP 發送數據之前無需建立連接;
- 服務對象,TCP 服務的對象為一對一的雙端應用,而 UDP 可以應用于一對一、一對多和多對多的通信場景;
- 效率,TCP 的傳輸效率較低,而 UDP 的傳輸效率較 高;
- 流量控制,TCP 有滑動窗口可以用來控制流量,而 UDP 則不具備流量控制的能力;
- 報文,TCP 是面向字節流的傳輸層協議,而 UDP 是面向報文的傳輸層協議;
- 應用場景,TCP 的應用場景是對消息準確性和順序要求較高的場景,而 UDP 則是應用于對通信效率較高、準確性要求相對較低的場景。
TCP 和 UDP 的使用場景如下圖所示:
小結
本課時我們介紹了 TCP 三個特點:面向連接、可靠性和面向字節流,其中可靠性主要是依賴它的狀態記錄和根據實際情況調整自身的行為方式。例如,當 TCP 意識到丟包時就會重發此包,這樣就保證了通信的可靠性。
TCP 之所以需要三次握手的主要原因是為了防止在網絡環境比較差的情況下不會進行無效的連接,同時三次握手可以實現 TCP 初始化序列號的確認工作,TCP 需要初始化一個序列號來保證消息的順序。如果是兩次握手則不能確認序列號是否正常,如果是四次握手的話會浪費系統的資源,因此 TCP 三次握手是最優的解決方案,所以 TCP 連接需要三次握手。
最后我們講了 UDP 的概念,以及 UDP 和 TCP 的區別,在傳輸效率要求比較高且對可靠性要求不高的情況下可以使用 UDP,反之則應該使用 TCP。