linux網絡編程之tcp的三次握手和四次揮手

一 .tcp協議的通信

tcp的通信過程分爲三個步驟:建立TCP連接通道,傳輸數據,斷開TCP連接通道

下圖爲tcp的通信過程示意圖:
這裏寫圖片描述
建立tcp連接通道:三次握手
斷開tcp連接通道:四次揮手

二.詳解三次握手和四次揮手

  • 三次握手建立連接:

    • 第一次握手:客戶端發送tcp報文到服務器,其中syn標誌位1,seq=x(x爲A的初始序列號,隨機數),然後啓動計時器,等待接收服務器的應答。該報文段成爲SYN報文段,不攜帶任何數據,但是消耗一個序列號。
    • 第二次握手:服務器收到客戶端的tcp連接請求後,向客戶端發出應答報文,其中SYN標誌和ASK都爲零,序列號爲y(y爲服務端的初始序列號,隨機數),確認號爲x+1,服務端也啓動計時器,等待接收客戶端的應答。這裏的服務器發送給客戶端的報文段稱爲SYN+ASK報文段,它不攜帶任何數據,但是消耗一個序列號。
    • 第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=y+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手。
      握手過程中傳送的包裏不包含數據,三次握手完畢後,客戶端與服務器才正式開始傳送數據。理想狀態下,TCP連接一旦建立,在通信雙方中的任何一方主動關閉連接之前,TCP 連接都將被一直保持下去。
  • 傳輸數據過程:
    a.超時重傳
    超時重傳機制用來保證TCP傳輸的可靠性。每次發送數據包時,發送的數據報都有seq號,接收端收到數據後,會回覆ack進行確認,表示某一seq號數據已經收到。發送方在發送了某個seq包後,等待一段時間,如果沒有收到對應的ack回覆,就會認爲報文丟失,會重傳這個數據包。
    b.快速重傳
    接受數據一方發現有數據包丟掉了。就會發送ack報文告訴發送端重傳丟失的報文。如果發送端連續收到標號相同的ack包,則會觸發客戶端的快速重傳。比較超時重傳和快速重傳,可以發現超時重傳是發送端在傻等超時,然後觸發重傳;而快速重傳則是接收端主動告訴發送端數據沒收到,然後觸發發送端重傳。
    c.流量控制
    這裏主要說TCP滑動窗流量控制。TCP頭裏有一個字段叫Window,又叫Advertised-Window,這個字段是接收端告訴發送端自己還有多少緩衝區可以接收數據。於是發送端就可以根據這個接收端的處理能力來發送數據,而不會導致接收端處理不過來。 滑動窗可以是提高TCP傳輸效率的一種機制。
    d.擁塞控制
    滑動窗用來做流量控制。流量控制只關注發送端和接受端自身的狀況,而沒有考慮整個網絡的通信情況。擁塞控制,則是基於整個網絡來考慮的。考慮一下這樣的場景:某一時刻網絡上的延時突然增加,那麼,TCP對這個事做出的應對只有重傳數據,但是,重傳會導致網絡的負擔更重,於是會導致更大的延遲以及更多的丟包,於是,這個情況就會進入惡性循環被不斷地放大。試想一下,如果一個網絡內有成千上萬的TCP連接都這麼行事,那麼馬上就會形成“網絡風暴”,TCP這個協議就會拖垮整個網絡。爲此,TCP引入了擁塞控制策略。擁塞策略算法主要包括:慢啓動,擁塞避免,擁塞發生,快速恢復。

  • 四次握手斷開連接:(以下的w,u,v均屬於隨機數)

    • 第一次揮手:主動關閉方發送一個FIN=1,序號爲seq=u,用來關閉主動方到被動關閉方的數據傳送,也就是主動關閉方告訴被動關閉方:我已經不會再給你發數據了(當然,在fin包之前發送出去的數據,如果沒有收到對應的ack確認報文,主動關閉方依然會重發這些數據),但此時主動關閉方還可以接受數據。
    • 第二次揮手:被動關閉方收到FIN包(即收到對方的釋放請求)後,發送一個ACK(確認報文)給對方,標誌ASK=1,序號爲seq=1,確認序號爲收到序號u+1。
    • 第三次揮手:被動關閉方接收到應用程序關閉的信息,向主動關閉方發送一個確認報文,FIN =1,ASK=1,序號爲seq=w,確認序號爲收到序號u+1。用來關閉被動關閉方到主動關閉方的數據傳送,也就是告訴主動關閉方,我的數據也發送完了,不會再給你發數據了。
    • 第四次揮手:主動關閉方收到確認報文後像被動方發出確認報文,標誌位ACK=1,序列號爲seq=v+1,確認序號爲收到序號即w+1,至此,完成四次揮手。

鏈接時要三次握手的理由

爲了防止已失效的連接請求報文段突然又傳送到了服務端,因而產生錯誤。
例如:
“已失效的連接請求報文段”的產生在這樣一種情況下:client發出的第一個連接請求報文段並沒有丟失,而是在某個網絡結點長時間的滯留了,以致延誤到連接釋放以後的某個時間纔到達server。本來這是一個早已失效的報文段。但server收到此失效的連接請求報文段後,就誤認爲是client再次發出的一個新的連接請求。於是就向client發出確認報文段,同意建立連接。假設不採用“三次握手”,那麼只要server發出確認,新的連接就建立了。由於現在client並沒有發出建立連接的請求,因此不會理睬server的確認,也不會向server發送數據。但server卻以爲新的運輸連接已經建立,並一直等待client發來數據。這樣,server的很多資源就白白浪費掉了。採用“三次握手”的辦法可以防止上述現象發生。例如剛纔那種情況,client不會向server的確認發出確認。server由於收不到確認,就知道client並沒有要求建立連接。”。主要目的防止server端一直等待,浪費資源。

爲什麼在連接時要三次握手在斷開時卻要四次揮手

因爲當Server端收到Client端的SYN連接請求報文後,可以直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連接時,當Server端收到FIN報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,”你發的FIN報文我收到了”。只有等到我Server端所有的報文都發送完了,我才能發送FIN報文,因此不能一起發送。故需要四步握手。

四次握手時,TIME_WAIT出現的理由

1.可靠地實現TCP全雙工連接的終止。

TCP協議在關閉連接的四次握手過程中,最終的ACK是由主動關閉連接的一端(後面統稱A端)發出的,如果這個ACK丟失,對方(後面統稱B端)將重發出最終的FIN,因此A端必須維護狀態信息(TIME_WAIT)允許它重發最終的ACK。如果A端不維持TIME_WAIT狀態,而是處於CLOSED 狀態,那麼A端將響應RST分節,B端收到後將此分節解釋成一個錯誤(在java中會拋出connection reset的SocketException)。
因而,要實現TCP全雙工連接的正常終止,必須處理終止過程中四個分節任何一個分節的丟失情況,主動關閉連接的A端必須維持TIME_WAIT狀態 。

2.允許老的重複分節在網絡中消逝。

TCP分節可能由於路由器異常而“迷途”,在迷途期間,TCP發送端可能因確認超時而重發這個分節,迷途的分節在路由器修復後也會被送到最終目的地,這個遲到的迷途分節到達時可能會引起問題。在關閉“前一個連接”之後,馬上又重新建立起一個相同的IP和端口之間的“新連接”,“前一個連接”的迷途重複分組在“前一個連接”終止後到達,而被“新連接”收到了。爲了避免這個情況,TCP協議不允許處於TIME_WAIT狀態的連接啓動一個新的可用連接,因爲TIME_WAIT狀態持續2MSL,就可以保證當成功建立一個新TCP連接的時候,來自舊連接重複分組已經在網絡中消逝。

爲什麼TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?

雖然按道理,四個報文都發送完畢,我們可以直接進入CLOSE狀態了,但是我們必須假象網絡是不可靠的,有可以最後一個ACK丟失。所以TIME_WAIT狀態就是用來重發可能丟失的ACK報文。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章