在TCP/IP協議中,TCP協議提供可靠的串連服務,採用三向交握建立一個串連,1所示。
(1)第一次握手:建立串連時,用戶端A發送SYN包(SYN=j)到伺服器B,並進入SYN_SEND狀態,等待伺服器B確認。
(2)第二次握手:伺服器B收到SYN包,必須確認客戶A的SYN(ACK=j+1),同時自己也發送一個SYN包(SYN=k),即SYN+ACK包,此時伺服器B進入SYN_RECV狀態。
(3)第三向交握:用戶端A收到伺服器B的SYN+ACK包,向伺服器B發送確認包ACK(ACK=k+1),此包發送完畢,用戶端A和伺服器B進入ESTABLISHED狀態,完成三向交握。
完成三向交握,用戶端與伺服器開始傳送資料。
圖1 TCP三向交握建立串連
由於TCP串連是全雙工系統的,因此每個方向都必須單獨進行關閉。這個原則是當一方完成它的資料發送任務後就能發送一個FIN來終止這個方向的串連。收到一個 FIN只意味著這一方向上沒有資料流動,一個TCP串連在收到一個FIN後仍能發送資料。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
(1)用戶端A發送一個FIN,用來關閉客戶A到伺服器B的資料傳送(報文段4)。
(2)伺服器B收到這個FIN,它發回一個ACK,確認序號為收到的序號加1(報文段5)。和SYN一樣,一個FIN將佔用一個序號。
(3)伺服器B關閉與用戶端A的串連,發送一個FIN給用戶端A(報文段6)。
(4)用戶端A發回ACK報文確認,並將確認序號設定為收到序號加1(報文段7)。
TCP採用四次揮手關閉串連2所示。
圖2 TCP四次揮手關閉串連
1.為什麼建立連線協定是三向交握,而關閉串連卻是四次握手呢?
這是因為服務端的LISTEN狀態下的SOCKET當收到SYN報文的建連請求後,它可以把ACK和SYN(ACK起應答作用,而SYN起同步作用)放在一個報文裡來發送。但關閉串連時,當收到對方的FIN報文通知時,它僅僅表示對方沒有資料發送給你了;但未必你所有的資料都全部發送給對方了,所以你可以未必會馬上會關閉SOCKET,也即你可能還需要發送一些資料給對方之後,再發送FIN報文給對方來表示你同意現在可以關閉串連了,所以它這裡的ACK報文和FIN報文多數情況下都是分開發送的。
2.為什麼TIME_WAIT狀態還需要等2MSL後才能返回到CLOSED狀態?
這是因為雖然雙方都同意關閉串連了,而且握手的4個報文也都協調和發送完畢,按理可以直接回到CLOSED狀態(就好比從SYN_SEND狀態到 ESTABLISH狀態那樣);但是因為我們必須要假想網路是不可靠的,你無法保證你最後發送的ACK報文會一定被對方收到,因此對方處於 LAST_ACK狀態下的SOCKET可能會因為逾時未收到ACK報文,而重發FIN報文,所以這個TIME_WAIT狀態的作用就是用來重發可能丟失的 ACK報文