Linux网络编程——浅谈 TCP 三次握手和四次挥手
一、tcp協議格式
二、三次握手
在 TCP/IP 協議中,TCP 協議提供可靠的連接服務,采用三次握手建立一個連接。
?
第一次握手:建立連接時,客戶端發送 syn 包(tcp協議中syn位置1,序號為J)到服務器,并進入 SYN_SEND 狀態,等待服務器確認;?
第二次握手:服務器收到 syn 包,必須確認客戶的 SYN,同時自己也發送一個 SYN 包,即 SYN+ACK包(tcp協議中syn位置1,ack位置1,序號K,確定序號為J+1),此時服務器進入 SYN_RECV 狀態;?
第三次握手:客戶端收到服務器的 SYN+ACK 包,向服務器發送確認包 ACK(tcp協議中ack位置1,確認序號K+1),此包發送完畢,客戶端和服務器進入 ESTABLISHED 狀態,完成三次握手。
?
通過這樣的三次握手,客戶端與服務端建立起可靠的雙工的連接,開始傳送數據。?三次握手的最主要目的是保證連接是雙工的,可靠更多的是通過重傳機制來保證的。但是為什么一定要進行三次握手來保證連接是雙工的呢,一次不行么?兩次不行么?
我們舉一個現實生活中兩個人進行語言溝通的例子來模擬三次握手。
第一次對話:?
老婆讓甲出去打醬油,半路碰到一個朋友乙,甲問了一句:哥們你吃飯了么??
結果乙帶著耳機聽歌呢,根本沒聽到,沒反應。甲心里想:跟你說話也沒個音,不跟你說了,溝通失敗。說明乙接受不到甲傳過來的信息的情況下溝通肯定是失敗的。
?
如果乙聽到了甲說的話,那么第一次對話成功,接下來進行第二次對話。?
第二次對話:?
乙聽到了甲說的話,但是他是老外,中文不好,不知道甲說的啥意思也不知道怎樣回答,于是隨便回答了一句學過的中文 :我去廁所了。甲一聽立刻笑噴了,“去廁所吃飯”?道不同不相為謀,離你遠點吧,溝通失敗。說明乙無法做出正確應答的情況下溝通失敗。?
如果乙聽到了甲的話,做出了正確的應答,并且還進行了反問:我吃飯了,你呢?那么第二次握手成功。?
通過前兩次對話證明了乙能夠聽懂甲說的話,并且能做出正確的應答。接下來進行第三次對話。?
第三次對話:?
甲剛和乙打了個招呼,突然老婆喊他,“你個死鬼,打個醬油咋這么半天,看我回家咋收拾你”,甲是個妻管嚴,聽完嚇得二話不說就跑回家了,把乙自己晾那了。乙心想:這什么人啊,得,我也回家吧,溝通失敗。說明甲無法做出應答的情況下溝通失敗。?
如果甲也做出了正確的應答:我也吃了。那么第三次對話成功,兩人已經建立起了順暢的溝通渠道,接下來開始持續的聊天。?
通過第二次和第三次的對話證明了甲能夠聽懂乙說的話,并且能做出正確的應答。?可見,兩個人進行有效的語言溝通,這三次對話的過程是必須的。
?
同理對于TCP為什么需要進行三次握手我們可以一樣的理解:?
為了保證服務端能收接受到客戶端的信息并能做出正確的應答而進行前兩次(第一次和第二次)握手,為了保證客戶端能夠接收到服務端的信息并能做出正確的應答而進行后兩次(第二次和第三次)握手。?
三、四次揮手
由于 TCP 連接是全雙工的,因此每個方向都必須單獨進行關閉。這好比,我們打電話(全雙工),正常的情況下(出于禮貌),通話的雙方都要說再見后才能掛電話,保證通信雙方都把話說完了才掛電話。
那TCP 的四次握手,是為了保證通信雙方都關閉了連接,具體過程如下:
1)客戶端 A 在應用層調用close時會激發底層發送一個 FIN(tcp協議中FIN位置1、序號為M,結合上圖分析)請求,用來關閉客戶 A 到服務器 B 的數據傳送,客戶端A此時處于半關閉狀態(應用層無法接收數據但底層還可以接收數據);
2)服務器 B 底層收到客戶端A的FIN時會做兩件事
2.1)第1件事:收到客戶端A的FIN時底層會主動回發一個ACK(tcp協議中ACK位置1,確認序號M+1)
2.2)第2件事:收到客戶端A的FIN時,導致服務器B的應用層read()返回0(告訴服務器B應用層:客戶端A關閉了)
3)服務器B應用層調用close()激發底層給客戶端 A 發送一個 FIN(tcp協議中FIN位置1、序號為N),這是服務器B已處于半關閉狀態;
4)客戶端 A 底層回發 ACK(tcp協議中ACK位置1,確認序號N+1) 給服務器B,這是客戶端A、服務器B都處于完全關閉狀態,回收相應的資源。
為什么建立連接協議是三次握手,而關閉連接卻是四次握手呢?
這是因為服務端的 LISTEN 狀態下的 SOCKET 當收到 SYN 報文的建連請求后,它可以把 ACK 和 SYN(ACK 起應答作用,而 SYN 起同步作用)放在一個報文里來發送。但關閉連接時,當收到FIN 報文通知時,如果能將ACK、FIN放在一個報文里那么就有了三次揮手,但是這是不可能,因為ACK是服務器B一收到FIN報文底層就回發的,而服務器B的FIN是應用層調用close()激發的,所以它這里的 ACK 報文和 FIN 報文在發送的時間上都是分開的,不可能同時發送。
為什么 TIME_WAIT 狀態還需要等 2MS L后才能返回到 CLOSED 狀態?
這是因為雖然雙方都同意關閉連接了,而且握手的 4 個報文也都協調和發送完畢,按理可以直接回到 CLOSED 狀態(就好比從 SYN_SEND 狀態到 ESTABLISH 狀態那樣);但是因為我們必須要假想網絡是不可靠的,你無法保證你最后發送的 ACK 報文會一定被對方收到,因此對方處于 LAST_ACK 狀態下的 SOCKET 可能會因為超時未收到 ACK 報文,而重發 FIN 報文,所以這個 TIME_WAIT 狀態的作用就是用來重發可能丟失的 ACK 報文。(里面涉及的狀態是什么意思,詳情請看《TCP 通信過程中各步驟的狀態》)
總結
以上是生活随笔為你收集整理的Linux网络编程——浅谈 TCP 三次握手和四次挥手的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OllyDbg完全教程
- 下一篇: TCP三次握手在linux内核中的实现