三次握手
第一次握手:客戶端向服務端發送請求連接的SYN報文,客戶端進入SYN_SENT狀態,等待服務端確認;
第二次握手:服務端收到客戶端的SYN報文,對SYN報文段進行確認,并向客戶端發送SYN+ACK報文,服務端進入SYN_RCVD狀態;
第三次握手:客戶端收到服務端的SYN+ACK報文,設置ACK報文,向服務端發送ACK報文,這個報文發送完畢后,客戶端和服務端都進入了ESTABLISH狀態,TCP連接成功,三次握手完成;
四次揮手
第一次揮手:客戶端向服務端發送斷開連接的FIN報文,客戶端進入FIN_WAIT狀態,表示沒有數據要發送給服務端了;
第二次揮手:服務端收到客戶端發送的FIN報文,向客戶端發送ACK報文;
第三次揮手:服務端向客戶端發送請求關閉連接的FIN報文,服務端進入LAST_ACK狀態;
第四次揮手:客戶端收到服務端發送的FIN報文,向服務端發送ACK報文,客戶端進入TIME_WAIT狀態。服務端收到客戶端發送的ACK報文后,關閉連接;此時如果客戶端等待響應的時間超過報文最大生存時間,則說明服務端已經正常關閉,客戶端也可以關閉連接了;
為什么TCP建立連接需三次握手?
防止服務端因收到了早已過期失效的客戶端請求連接報文,而不斷等待客戶端的請求,從而造成死鎖狀態,浪費資源。因為如果在第一次握手的時候,也就是客戶端發送請求連接的報文給服務端時,如果此報文因為某種原因在網絡節點上長時間滯留,導致延遲到連接釋放之后的某個時間才到達服務端,那么這時候服務端會認為是客戶端重新發送的新的請求連接報文,但實際上已經是失效的報文。如果只是經過二次握手,那么第二次握手服務端向客戶端發送確認請求連接報文并建立連接,這個時候就會導致客戶端并沒有建立連接,而服務端已經建立連接的情況,那么服務端就會一直等待客戶端發送請求數據,而客戶端因未建立連接并不會發起任何請求,從而造成死鎖狀態。如果采用三次握手就不會出現上述情況,因為第三次握手時客戶端知道自己的報文已經失效了,不會向服務端發送的確認連接報文進行再次確認,當服務端沒有再次收到客戶端再次確認請求連接的報文時就會知道客戶端并無建立TCP連接的請求,故服務器也就不會一直等待客戶端發送請求了。
為什么建立連接協議是三次握手,而關閉連接卻是四次揮手呢?
TCP是全雙工的雙向通信方式,即連接雙方都可以發送和接受數據,在斷開TCP連接時需要雙方都關閉連接,才算真正關閉TCP連接,否則如果只有一方斷開連接,那就只是處于TCP半關閉狀態。
第一次揮手客戶端發起釋放連接的請求給服務端,表示沒有數據要發送給服務端了;第二次揮手服務端返回確認釋放連接的報文給客戶端,此時客戶端到服務端的連接已經關閉,但是服務端到客戶端的連接依然存在,服務端依然可以返回響應數據給客戶端,TCP出于半關閉狀態;所以服務端需要進行第三次揮手,發送釋放連接的報文給客戶端,表示沒有數據要發送給客戶端了,客戶端收到報文后再返回確認釋放連接的報文給服務端,并等待服務端的關閉,當服務端收到客戶端的釋放連接報文后就關閉連接,客戶端等待超過報文最長生存時間后也關閉連接,此時服務端到客戶端的連接才真正釋放,即TCP連接真正關閉。
第一次揮手時客戶端發送FIN報文給服務端僅表示及沒有數據要發送給服務端了,但是這時候可能服務端還有數據要傳輸給客戶端,所以不能同時發送ACK報文和FIN報文馬上斷開連接,需要先發送ACK報文通知客戶端數據已經傳輸完成了,再發送FIN報文進行確認關閉連接的信息通知客戶端,所以需要進行四次揮手。
為什么客戶端關閉連接前要等待2MSL時間?
原因是最后一次客戶端發送的確認連接釋放的請求有可能會失效(第四次揮手),如果失效了服務端就接收不到確認連接的報文,那么這時候服務端會重新發送釋放連接的報文(第三次揮手),如果此時客戶端沒有等待2MSL時間直接關閉連接的話,那么客戶端就會接收不到服務端再次發送的釋放連接報文,此時客戶端處于關閉狀態,但是服務端處于未關閉狀態,導致TCP斷開連接失敗。
參考
《Android進階之光》 第5章 5.2 TCP的三次握手與四次揮手