1. 程式人生 > 其它 >TCP的三次握手與四次揮手

TCP的三次握手與四次揮手

介紹

TCP是一種面向連線的、可靠的、基於位元組流的傳輸層通訊協議,在傳送資料前,通訊雙方必須在彼此間建立一條連線。所謂的“連線”,其實是客戶端和服務端儲存的一份關於對方的資訊,如ip地址、埠號等。

TCP可以看成是一種位元組流,它會處理IP層或以下的層的丟包、重複以及錯誤問題。在連線的建立過程中,雙方需要交換一些連線的引數。這些引數可以放在TCP頭部。

TCP提供了一種可靠、面向連線、位元組流、傳輸層的服務,採用三次握手建立一個連線。採用4次揮手來關閉一個連線。

TCP服務模型

在瞭解了建立連線、關閉連線的“三次握手和四次揮手”後,我們再來看下TCP相關的東西。

一個TCP連線由一個4元組構成,分別是兩個IP地址和兩個埠號。一個TCP連線通常分為三個階段:啟動、資料傳輸、退出(關閉)。

當TCP接收到另一端的資料時,它會發送一個確認,但這個確認不會立即傳送,一般會延遲一會兒。ACK是累積的,一個確認位元組號N的ACK表示所有直到N的位元組(不包括N)已經成功被接收了。這樣的好處是如果一個ACK丟失,很可能後續的ACK就足以確認前面的報文段了。

一個完整的TCP連線是雙向和對稱的,資料可以在兩個方向上平等地流動。給上層應用程式提供一種雙工服務。一旦建立了一個連線,這個連線的一個方向上的每個TCP報文段都包含了相反方向上的報文段的一個ACK。

序列號的作用是使得一個TCP接收端可丟棄重複的報文段,記錄以雜亂次序到達的報文段。因為TCP使用IP來傳輸報文段,而IP不提供重複消除或者保證次序正確的功能。另一方面,TCP是一個位元組流協議,絕不會以雜亂的次序給上層程式傳送資料。因此TCP接收端會被迫先保持大序列號的資料不交給應用程式,直到缺失的小序列號的報文段被填滿。

TCP報文的頭部結構

在瞭解TCP連線之前先來了解一下TCP報文的頭部結構。

源埠和目的埠在TCP層確定雙方程序,序列號表示的是報文段資料中的第一個位元組號,ACK表示確認號,該確認號的傳送方期待接收的下一個序列號,即最後被成功接收的資料位元組序列號加1,這個欄位只有在ACK位被啟用的時候才有效。

當新建一個連線時,從客戶端傳送到服務端的第一個報文段的SYN位被啟用,這稱為SYN報文段,這時序列號欄位包含了在本次連線的這個方向上要使用的第一個序列號,即初始序列號ISN,之後傳送的資料是ISN加1,因此SYN位欄位會消耗一個序列號,這意味著使用重傳進行可靠傳輸。而不消耗序列號的ACK則不是。

上圖中有幾個欄位需要重點介紹下:

(1)序號:seq序號,佔32位,用來標識從TCP源端向目的端傳送的位元組流,發起方傳送資料時對此進行標記。

(2)確認序號:ack序號,佔32位,只有ACK標誌位為1時,確認序號欄位才有效,ack=seq+1。

(3)標誌位:共6個,即URG、ACK、PSH、RST、SYN、FIN等,具體含義如下:

ACK:確認序號有效。
FIN:釋放一個連線。
PSH:接收方應該儘快將這個報文交給應用層。
RST:重置連線。
SYN:發起一個新連線。
URG:緊急指標(urgent pointer)有效。

需要注意的是:

不要將確認序號ack與標誌位中的ACK搞混了。
確認方ack=發起方seq+1,兩端配對。

當一個連線被建立或被終止時,交換的報文段只包含TCP頭部,而沒有資料。

三次握手

三次握手的本質是確認通訊雙方收發資料的能力

換個易於理解的視角來看為什麼要3次握手。

客戶端和服務端通訊前要進行連線,“3次握手”的作用就是雙方都能明確自己和對方的收、發能力是正常的。

第一次握手:客戶端傳送網路包,服務端收到了。這樣服務端就能得出結論:客戶端的傳送能力、服務端的接收能力是正常的。

第二次握手:服務端發包,客戶端收到了。這樣客戶端就能得出結論:服務端的接收、傳送能力,客戶端的接收、傳送能力是正常的。 從客戶端的視角來看,我接到了服務端傳送過來的響應資料包,說明服務端接收到了我在第一次握手時傳送的網路包,並且成功傳送了響應資料包,這就說明,服務端的接收、傳送能力正常。而另一方面,我收到了服務端的響應資料包,說明我第一次傳送的網路包成功到達服務端,這樣,我自己的傳送和接收能力也是正常的。

第三次握手:客戶端發包,服務端收到了。這樣服務端就能得出結論:客戶端的接收、傳送能力,服務端的傳送、接收能力是正常的。 第一、二次握手後,服務端並不知道客戶端的接收能力以及自己的傳送能力是否正常。而在第三次握手時,服務端收到了客戶端對第二次握手作的迴應。從服務端的角度,我在第二次握手時的響應資料傳送出去了,客戶端接收到了。所以,我的傳送能力是正常的。而客戶端的接收能力也是正常的。

經歷了上面的三次握手過程,客戶端和服務端都確認了自己的接收、傳送能力是正常的。之後就可以正常通訊了。

每次都是接收到資料包的一方可以得到一些結論,傳送的一方其實沒有任何頭緒。我雖然有發包的動作,但是我怎麼知道我有沒有發出去,而對方有沒有接收到呢?

而從上面的過程可以看到,最少是需要三次握手過程的。兩次達不到讓雙方都得出自己、對方的接收、傳送能力都正常的結論。其實每次收到網路包的一方至少是可以得到:對方的傳送、我方的接收是正常的。而每一步都是有關聯的,下一次的“響應”是由於第一次的“請求”觸發,因此每次握手其實是可以得到額外的結論的。比如第三次握手時,服務端收到資料包,表明看服務端只能得到客戶端的傳送能力、服務端的接收能力是正常的,但是結合第二次,說明服務端在第二次傳送的響應包,客戶端接收到了,並且作出了響應,從而得到額外的結論:客戶端的接收、服務端的傳送是正常的。

四次揮手

四次揮手的目的是關閉一個連線

TCP連線是雙向傳輸的對等的模式,就是說雙方都可以同時向對方傳送或接收資料。當有一方要關閉連線時,會發送指令告知對方,我要關閉連線了。這時對方會回一個ACK,此時一個方向的連線關閉。但是另一個方向仍然可以繼續傳輸資料,等到傳送完了所有的資料後,會發送一個FIN段來關閉此方向上的連線。接收方傳送ACK確認關閉連線。注意,接收到FIN報文的一方只能回覆一個ACK, 它是無法馬上返回對方一個FIN報文段的,因為結束資料傳輸的“指令”是上層應用層給出的,我只是一個“搬運工”,我無法瞭解“上層的意志”。

“三次握手,四次揮手”怎麼完成?

其實3次握手的目的並不只是讓通訊雙方都瞭解到一個連線正在建立,還在於利用資料包的選項來傳輸特殊的資訊,交換初始序列號ISN。

3次握手是指傳送了3個報文段,4次揮手是指傳送了4個報文段。注意,SYN和FIN段都是會利用重傳進行可靠傳輸的。

三次握手

  1. 客戶端傳送一個SYN段,並指明客戶端的初始序列號,即ISN(c).
  2. 服務端傳送自己的SYN段作為應答,同樣指明自己的ISN(s)。為了確認客戶端的SYN,將ISN(c)+1作為ACK數值。這樣,每傳送一個SYN,序列號就會加1. 如果有丟失的情況,則會重傳。
  3. 為了確認伺服器端的SYN,客戶端將ISN(s)+1作為返回的ACK數值。

四次揮手

  1. 客戶端傳送一個FIN段,幷包含一個希望接收者看到的自己當前的序列號K. 同時還包含一個ACK表示確認對方最近一次發過來的資料。

  2. 服務端將K值加1作為ACK序號值,表明收到了上一個包。這時上層的應用程式會被告知另一端發起了關閉操作,通常這將引起應用程式發起自己的關閉操作。

  3. 服務端發起自己的FIN段,ACK=K+1, Seq=L 4. 客戶端確認。ACK=L+1

為什麼建立連線是三次握手,而關閉連線卻是四次揮手呢?

這是因為服務端在LISTEN狀態下,收到建立連線請求的SYN報文後,把ACK和SYN放在一個報文裡傳送給客戶端。而關閉連線時,當收到對方的FIN報文時,僅僅表示對方不再發送資料了但是還能接收資料,己方是否現在關閉傳送資料通道,需要上層應用來決定,因此,己方ACK和FIN一般都會分開發送。