網絡基礎知識 | TCP 三次握手和四次揮手(動畫版 & 女友版)

 

動畫版面試

 

TCP三次握手和四次揮手的問題在面試中是最爲常見的考點之一。不少讀者都知道三次和四次,可是若是問深刻一點,他們每每都沒法做出準確回答。編程

 

本篇嘗試使用動畫來對這個知識點進行講解,指望讀者們能夠更加簡單地地理解TCP交互的本質。服務器

 

TCP 三次握手

 

TCP 三次握手就比如兩我的在街上隔着50米看見了對方,可是由於霧霾等緣由不能100%確認,因此要經過招手的方式相互肯定對方是否定識本身。網絡

 

張三首先向李四招手(syn),李四看到張三向本身招手後,向對方點了點頭擠出了一個微笑(ack)。張三看到李四微笑後確認了李四成功辨認出了本身(進入estalished狀態)。socket

 

可是李四還有點狐疑,向四周看了一看,有沒有可能張三是在看別人呢,他也須要確認一下。tcp

 

因此李四也向張三招了招手(syn),張三看到李四向本身招手後知道對方是在尋求本身的確認,因而也點了點頭擠出了微笑(ack),李四看到對方的微笑後確認了張三就是在向本身打招呼(進入established狀態)。學習

 

因而兩人加快步伐,走到了一塊兒,相互擁抱。動畫

 

咱們看到這個過程當中一共是四個動做,張三招手--李四點頭微笑--李四招手--張三點頭微笑。操作系統

 

其中李四連續進行了2個動做,先是點頭微笑(回覆對方),而後再次招手(尋求確認),實際上能夠將這兩個動做合一,招手的同時點頭和微笑(syn+ack)。指針

 

因而四個動做就簡化成了三個動做,張三招手--李四點頭微笑並招手--張三點頭微笑。這就是三次握手的本質,中間的一次動做是兩個動做的合併。

 

咱們看到有兩個中間狀態,syn_sent和syn_rcvd,這兩個狀態叫着「半打開」狀態,就是向對方招手了,可是還沒來得及看到對方的點頭微笑。

 

syn_sent是主動打開方的「半打開」狀態,syn_rcvd是被動打開方的「半打開」狀態。客戶端是主動打開方,服務器是被動打開方。

 

syn_sent: syn package has been sent

syn_rcvd: syn package has been received

 

TCP 數據傳輸

 

TCP 數據傳輸就是兩我的隔空對話,差了一點距離,因此須要對方反覆確認聽見了本身的話。

 

張三喊了一句話(data),李四聽見了以後要向張三回覆本身聽見了(ack)。

 

若是張三喊了一句,半天沒聽到李四回覆,張三就認爲本身的話被大風吹走了,李四沒聽見,因此須要從新喊話,這就是tcp重傳。

 

也有多是李四聽到了張三的話,可是李四向張三的回覆被大風吹走了,以致於張三沒聽見李四的回覆。

 

張三並不能判斷到底是本身的話被大風吹走了仍是李四的回覆被大風吹走了,張三也不用管,重傳一下就是。

 

既然會重傳,李四就有可能同一句話聽見了兩次,這就是「去重」。「重傳」和「去重」工做操做系統的網絡內核模塊都已經幫咱們處理好了,用戶層是不用關心的。

 

張三能夠向李四喊話,一樣李四也能夠向張三喊話,由於tcp連接是「雙工的」,雙方均可以主動發起數據傳輸。不過不管是哪方喊話,都須要收到對方的確認才能認爲對方收到了本身的喊話。

 

張三多是個高射炮,一說連說了八句話,這時候李四能夠不用一句一句回覆,而是連續聽了這八句話以後,一塊兒向對方回覆說前面你說的八句話我都聽見了,這就是批量ack。

 

可是張三也不能一次性說了太多話,李四的腦子短期可能沒法消化太多,兩人之間須要有協商好的合適的發送和接受速率,這個就是「TCP窗口大小」。

 

網絡環境的數據交互同人類之間的對話還要複雜一些,它存在數據包亂序的現象。

 

同一個來源發出來的不一樣數據包在「網際路由」上可能會走過不一樣的路徑,最終達到同一個地方時,順序就不同了。

 

操做系統的網絡內核模塊會負責對數據包進行排序,到用戶層時順序就已經徹底一致了。

 

TCP 四次揮手

 

TCP斷開連接的過程和創建連接的過程比較相似,只不過中間的兩部並不老是會合成一步走,因此它分紅了4個動做,張三揮手(fin)——李四傷感地微笑(ack)——李四揮手(fin)——張三傷感地微笑(ack)。

 

之因此中間的兩個動做沒有合併,是由於tcp存在「半關閉」狀態,也就是單向關閉。

 

張三已經揮了手,但是人尚未走,只是再也不說話,可是耳朵仍是能夠繼續聽,李四呢繼續喊話。等待李四累了,也再也不說話了,超張三揮了揮手,張三傷感地微笑了一下,才完全結束了。

 

 

上面有一個很是特殊的狀態time_wait,它是主動關閉的一方在回覆完對方的揮手後進入的一個長期狀態,這個狀態標準的持續時間是4分鐘,4分鐘後纔會進入到closed狀態,釋放套接字資源。不過在具體實現上這個時間是能夠調整的。

 

它就比如主動分手方要承擔的責任,是你提出的要分手,你得付出代價。這個後果就是持續4分鐘的time_wait狀態,不能釋放套接字資源(端口),就比如守寡期,這段時間內套接字資源(端口)不得回收利用。

 

它的做用是重傳最後一個ack報文,確保對方能夠收到。由於若是對方沒有收到ack的話,會重傳fin報文,處於time_wait狀態的套接字會當即向對方重發ack報文。

 

同時在這段時間內,該連接在對話期間於網際路由上產生的殘留報文(由於路徑過於崎嶇,數據報文走的時間太長,重傳的報文都收到了,原始報文還在路上)傳過來時,都會被當即丟棄掉。

 

4分鐘的時間足以使得這些殘留報文完全消逝。否則當新的端口被重複利用時,這些殘留報文可能會干擾新的連接。

 

4分鐘就是2個MSL,每一個MSL是2分鐘。MSL就是maximium segment lifetime——最長報文壽命。這個時間是由官方RFC協議規定的。至於爲何是2個MSL而不是1個MSL,我尚未看到一個很是滿意的解釋。

 

四次揮手也並不老是四次揮手,中間的兩個動做有時候是能夠合併一塊兒進行的,這個時候就成了三次揮手,主動關閉方就會從fin_wait_1狀態直接進入到time_wait狀態,跳過了fin_wait_2狀態。

 

總結

 

TCP狀態轉換是一個很是複雜的過程,本文僅對一些簡單的基礎知識點進行了類比講解。關於TCP的更多知識還須要讀者去查看相關技術文章書籍進入深刻學習。若是讀者對TCP的基礎知識掌握得比較牢固,高級的知識理解起來就不會太過於吃力。

 

女友版

背景

 

和女友異地戀一年多,爲了保持感情我提議天天晚上視頻聊天一次。

從好上開始,到如今,一年多也算堅持下來了。

問題

有時候聊天的過程當中,個人網絡或者她的網絡可能會很差,視頻就會卡住,聽不到對方的聲音,過一下子以後纔會恢復。

中間雙方可能就要不斷的確認網絡是否恢復,可是有時候會:

她:「你能夠聽到了嗎?」

我:「能夠了,你呢?」、

她:「喂喂,你能夠聽到了嗎?」

我:「能夠了,我能夠聽到了,你呢?」

她:「你能夠聽到了嗎?」

.....

這種狀況很蛋疼,那麼怎樣才能找一個簡單的辦法,讓兩我的都確認本身能夠聽到對方的聲音,對方也能夠聽到本身的聲音呢?

 

方案

 

TCP創建鏈接爲何是三次握手,而不是兩次或四次?

TCP,名爲傳輸控制協議,是一種可靠的傳輸層協議,IP協議號爲6。

順便說一句,原則上任何數據傳輸都沒法確保絕對可靠,三次握手只是確保可靠的基本須要。

舉個平常例子,打電話時咱們對話以下:

 

對應爲客戶端與服務器之間的通訊:

 

 

 

 

 

 

 

 

 

因而有了以下對話:

我:1+1等於幾?

她:2,2+2等於幾?

我:4

首先兩我的約定協議:

(1)感受網絡狀況不對的時候,任何一方均可以發起詢問

(2)任何狀況下,若發起詢問後5秒還沒收到回覆,則認爲網絡不通

(3)網絡不通的狀況下等1min路由器以後再發起詢問

 

對於我而言,發起 「1+1等於幾」的詢問後:

(1) 若5s內沒有收到回覆,則認爲網絡不通

(2) 若收到回覆,則我確認①我能聽到她的消息 ②她能聽到個人消息,而後回覆她的問題的答案

 

對於她而言,當感受網絡狀況不對的時候:

(1) 若沒有收到個人詢問,則她發起詢問

(2) 若收到「1+1等於幾」,則她確認 ①她能夠聽到個人消息,而後回覆個人問題的答案和她的問題「2,2+2等於幾」

(3) 若5s內沒有收到個人回覆「4」,則她確認 ②我聽不見她的消息

(4) 若5s內收到了個人回覆「4」,則她確認 ②我能夠聽見她的消息

這樣,若是上面的對話得以完成,就證實雙方均可以確認本身能夠聽到對方的聲音,對方也能夠聽到本身的聲音!

這個故事能夠解釋TCP爲何要三次握手嗎 ... 囧

 

關於四次揮手

 

先由客戶端向服務器端發送一個FIN,請求關閉數據傳輸。

當服務器接收到客戶端的FIN時,向客戶端發送一個ACK,其中ack的值等於FIN+SEQ

而後服務器向客戶端發送一個FIN,告訴客戶端應用程序關閉。

當客戶端收到服務器端的FIN是,回覆一個ACK給服務器端。其中ack的值等於FIN+SEQ

 

爲何要4次揮手?

 

確保數據可以完整傳輸。

當被動方收到主動方的FIN報文通知時,它僅僅表示主動方沒有數據再發送給被動方了。

但未必被動方全部的數據都完整的發送給了主動方,因此被動方不會立刻關閉SOCKET,它可能還須要發送一些數據給主動方後,

再發送FIN報文給主動方,告訴主動方贊成關閉鏈接,因此這裏的ACK報文和FIN報文多數狀況下都是分開發送的。

一、TCP報文格式

 

TCP報文格式圖:

 

 

上圖中有幾個字段須要重點介紹下:

(1)序號:Seq序號,佔32位,用來標識從TCP源端向目的端發送的字節流,發起方發送數據時對此進行標記。

(2)確認序號:Ack序號,佔32位,只有ACK標誌位爲1時,確認序號字段纔有效,Ack=Seq+1。

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

(A)URG:緊急指針(urgent pointer)有效。

(B)ACK:確認序號有效。

(C)PSH:接收方應該儘快將這個報文交給應用層。

(D)RST:重置鏈接。

(E)SYN:發起一個新鏈接。

(F)FIN:釋放一個鏈接。

須要注意的是:

(A)不要將確認序號Ack與標誌位中的ACK搞混了。

(B)確認方Ack=發起方Req+1,兩端配對。 

二、三次握手

 

TCP(Transmission Control Protocol) 傳輸控制協議

TCP是主機對主機層的傳輸控制協議,提供可靠的鏈接服務,採用三次握手確認創建一個鏈接

位碼即TCP標誌位,有6種標示:

  • SYN(synchronous創建聯機)

  • ACK(acknowledgement 確認)

  • PSH(push傳送)

  • FIN(finish結束)

  • RST(reset重置)

  • URG(urgent緊急)

Sequence number(順序號碼)

Acknowledge number(確認號碼)

establish  創建,建立

所謂三次握手(Three-Way Handshake)即創建TCP鏈接,是指創建一個TCP鏈接時,須要客戶端和服務端總共發送3個包以確認鏈接的創建。在socket編程中,這一過程由客戶端執行connect來觸發,整個流程以下圖所示:

 

 

(1)第一次握手:Client將標誌位SYN置爲1,隨機產生一個值seq=J,並將該數據包發送給Server,Client進入SYN_SENT狀態,等待Server確認。

(2)第二次握手:Server收到數據包後由標誌位SYN=1知道Client請求創建鏈接,Server將標誌位SYN和ACK都置爲1,ack (number )=J+1,隨機產生一個值seq=K,並將該數據包發送給Client以確認鏈接請求,Server進入SYN_RCVD狀態。

(3)第三次握手:Client收到確認後,檢查ack是否爲J+1,ACK是否爲1,若是正確則將標誌位ACK置爲1,ack=K+1,並將該數據包發送給Server,Server檢查ack是否爲K+1,ACK是否爲1,若是正確則鏈接創建成功,Client和Server進入ESTABLISHED狀態,完成三次握手,隨後Client與Server之間能夠開始傳輸數據了。 

 

SYN攻擊:

在三次握手過程當中,Server發送SYN-ACK以後,收到Client的ACK以前的TCP鏈接稱爲半鏈接(half-open connect),此時Server處於SYN_RCVD狀態,當收到ACK後,Server轉入ESTABLISHED狀態。SYN攻擊就是Client在短期內僞造大量不存在的IP地址,並向Server不斷地發送SYN包,Server回覆確認包,並等待Client的確認,因爲源地址是不存在的,所以,Server須要不斷重發直至超時,這些僞造的SYN包將長時間佔用未鏈接隊列,致使正常的SYN請求由於隊列滿而被丟棄,從而引發網絡堵塞甚至系統癱瘓。SYN攻擊時一種典型的DDOS攻擊,檢測SYN攻擊的方式很是簡單,即當Server上有大量半鏈接狀態且源IP地址是隨機的,則能夠判定遭到SYN攻擊了,使用以下命令可讓之現行:

#netstat -nap | grep SYN_RECV 

三、四次揮手

 

三次握手耳熟能詳,四次揮手估計就..所謂四次揮手(Four-Way Wavehand)即終止TCP鏈接,就是指斷開一個TCP鏈接時,須要客戶端和服務端總共發送4個包以確認鏈接的斷開。在socket編程中,這一過程由客戶端或服務端任一方執行close來觸發,整個流程以下圖所示:

因爲TCP鏈接時全雙工的,所以,每一個方向都必需要單獨進行關閉,這一原則是當一方完成數據發送任務後,發送一個FIN來終止這一方向的鏈接,收到一個FIN只是意味着這一方向上沒有數據流動了,即不會再收到數據了,可是在這個TCP鏈接上仍然可以發送數據,直到這一方向也發送了FIN。首先進行關閉的一方將執行主動關閉,而另外一方則執行被動關閉,上圖描述的便是如此。

(1)第一次揮手:Client發送一個FIN,用來關閉Client到Server的數據傳送,Client進入FIN_WAIT_1狀態。

(2)第二次揮手:Server收到FIN後,發送一個ACK給Client,確認序號爲收到序號+1(與SYN相同,一個FIN佔用一個序號),Server進入CLOSE_WAIT狀態。

(3)第三次揮手:Server發送一個FIN,用來關閉Server到Client的數據傳送,Server進入LAST_ACK狀態。

(4)第四次揮手:Client收到FIN後,Client進入TIME_WAIT狀態,接着發送一個ACK給Server,確認序號爲收到序號+1,Server進入CLOSED狀態,完成四次揮手。

 

上面是一方主動關閉,另外一方被動關閉的狀況,實際中還會出現同時發起主動關閉的狀況,具體流程以下圖:

 

  

流程和狀態在上圖中已經很明瞭了,在此再也不贅述,能夠參考前面的四次揮手解析步驟。

四、附註

 

關於三次握手與四次揮手一般都會有典型的面試題,在此提出供有需求的XDJM們參考:

(1)三次握手是什麼或者流程?四次握手呢?答案前面分析就是。

(2)爲何創建鏈接是三次握手,而關閉鏈接倒是四次揮手呢?

這是由於服務端在LISTEN狀態下,收到創建鏈接請求的SYN報文後,把ACK和SYN放在一個報文裏發送給客戶端。而關閉鏈接時,當收到對方的FIN報文時,僅僅表示對方再也不發送數據了可是還能接收數據,己方也未必所有數據都發送給對方了,因此己方能夠當即close,也能夠發送一些數據給對方後,再發送FIN報文給對方來表示贊成如今關閉鏈接,所以,己方ACK和FIN通常都會分開發送。

相關文章
相關標籤/搜索