拜託面試不要再問我TCP三次握手與四次揮手了

摘要

在互聯網大廠面試過程當中關於計算機中網絡常問的一個問題就是關於傳輸層裏面的協議:TCP協議,TCP協議規定了網絡通訊中點對點的通訊,基於PORT尋址到對應的主機上的某一個應用程序(一個網絡數據包過來以後,因爲各個應用程序是共用一塊網卡接收網絡數據包數據,因此爲了確認此網絡數據包究竟是發給我本機的哪一個應用程序的呢?QQ、微信、釘釘等,於是引出了TCP協議基於port的點對點通訊,TCP協議定一個一套規範,實際電腦網絡通訊的過程當中使用的是底層實現了tcp協議的編程規範的socket來進行點對點通訊),TCP協議進行通訊的關鍵步驟:點對點創建鏈接(TCP三次握手)、流失拆分數據傳輸、點對點釋放鏈接(TCP四次揮手)。java

面試題分析

一、畫一下TCP三次握手的流程圖?爲啥是三次而不是二次或者四次呢?而後連環炮追問,說一下TCP四次握手的過程?面試

背景

咱們經常使用的使用tcp協議編程主要是:socket編程,好比netty、java nio、socket等;基於ip地址加端口號進行點對點通訊時候實際上是很是基礎的。會經歷一個tcp的3次握手過程創建鏈接、而後傳輸數據,最後通過四次揮手釋放鏈接。編程

內容

三次握手主要是傳遞報頭數據:ACK,SYN,ack,seq;服務器

1_TCP三次握手/四次分手傳遞報頭數聽說明

image.png
TCP數據包由包頭跟數據組成;包頭主要由發送方端口跟接收方端口組成,以及每次我發送的數據包的起始字節數據序號seq,以及對每次發送者的確認號ack; 微信

TCP的3次握手是在進行數據傳輸發送前的準備工做,因此只須要交換一些頭部信息(說明性描述信息),因此咱們先弄清楚下信息交換的描述性信息: 網絡

序列號: TCP數據包的第一個字節數據編號(TCP把鏈接中發送的全部數據字節都編上一個序號,佔4個字節,32位,用來標記數據段的順序)。
確認號ack:期待收到對方下一個報文段的第一個數據字節的序號()。
確認ACK:用來限定說明確認號ack.僅當ACK=1時,確認號字段纔有效。ACK=0時,確認號無效(佔1位)。
同步SYN: 創建鏈接時候的同步序列,當SYN=1,ACK=0時表示:這是一個鏈接請求報文段(若贊成鏈接,則在響應報文段中使得SYN=1,ACK=1。所以,SYN=1表示這是一個鏈接請求,或鏈接接受報文。SYN這個標誌位只有在TCP建產鏈接時纔會被置1,握手完成後SYN標誌位被置0)。
終止FIN:用來釋放一個鏈接。FIN=1表示:此報文段的發送方的數據已經發送完畢,並要求釋放運輸鏈接。socket

:ACK、SYN和FIN這些大寫的單詞表示標誌位,其值要麼是1,要麼是0;ack、seq小寫的單詞表示序號。tcp

2_TCP三次握手圖解.


理清畫出tcp三次握手的核心思路:交換數據+進入的狀態
第一次握手:客戶端主動發起鏈接請求,發送:SYN=1,ACK=0,seq=x,此時客戶端進入SYN-SENT(同步發送)狀態。
第二次握手:服務端接收到客戶端發起鏈接請求,而後回覆贊成創建鏈接:SYN=1,ACK=1,ack=x+1,seq=y,此時服務端進入:SYN-RCVD(同步接收狀態)。
第三次握手:客戶端收到服務端統一創建鏈接的請求,而後發送準備就緒:ACK=1,ack=y+1,seq=x+1(由於已經創建了鏈接,因此再也不發送SYN,而ACK=1是確保ack有效的),此時客戶端進入ESTA-BLISHED狀態,服務端收到數據以後也會進入ESTA-BLISHED狀態。而後進入數據傳輸。spa

3_TCP四次握手圖解


第一次揮手:客戶端在ESTA-BLISHED已鏈接的狀態下發起釋放鏈接請求:FIN=1,seq=u,此時客戶端進入FIN-WAIT1(終止等待狀態1),此時客戶端再也不發送數據。.net

第二次揮手:服務端在接受到鏈接釋放請求後,發送確認消息:ACK=1,ack=u+1,seq=v;此時服務端進入關閉等待狀態,此時服務端會通知應用程序作鏈接關閉的準備工做.客戶端收到確認消息以後進入FIN-WAIT2(終止等待2狀態)。

第三次揮手:服務端作完鏈接關閉準備工做以後,通知服務端發送鏈接關閉請求給客戶端:FIN=1,seq=w;此時服務端進入LAST-ACK狀態。

第四次揮手:客戶端接受到服務端的鏈接釋放消息以後發送確認消息:ACK=1,ack=w+1,seq=u+1,此時客戶端進入時間等待狀態,在2MSL時間段內,關閉鏈接進入鏈接TIME_WAIT時間等待狀態。服務端收到消息以後進入CLOSED。

4_常見面試題擴展

一、傳輸層數據發送都須要創建鏈接嗎?說說TCP跟UDP協議的區別?

爲何須要握手這個操做,能不能不握手?在網絡上發送數據包事能夠不用握手的,使用握手的原理僅僅是爲了知足在不可靠信道上可靠地傳輸信息;對於主機電腦網卡而言,不一樣主機間發送數據包,先發的數據A並不必定比後發的數據B先到。只是TCP協議會作特殊處理而已。

若是讀者對比一下UDP的通訊流程和TCP的通訊流程,能夠發現:在UDP協議中,是沒有握手這個操做的。
image.png

這裏就引出了TCP與UDP的一個基本區別,TCP是可靠通訊協議,而UDP是不可靠通訊協議。
TCP的可靠性含義:接收方收到的數據是完整,有序,無差錯的。
UDP不可靠性含義:接收方接收到的數據可能存在部分丟失,順序也不必定能保證。
UDP和TCP協議都是基於一樣的互聯網基礎設施,且都基於IP協議實現,互聯網基礎設施中對於數據包的發送過程是會發生丟包現象的,爲何TCP就能夠實現可靠傳輸而UDP不行?

TCP 協議爲了實現可靠傳輸,通訊雙方須要判斷本身已經發送的數據包是否都被接收方收到,若是沒收到,就須要重發。爲了實現這個需求,很天然地就會引出序號(sequence number) 和 確認號(acknowledgement number)的使用。

發送方在發送數據包(假設大小爲10byte)時,同時送上一個序號(假設爲100),那麼接收方收到這個數據包之後,就能夠回覆一個確認號(110 = 100 + 10) 告訴發送方 「我已經收到了你的數據包, 你能夠發送下一個數據包序號從 110 開始」 。

二、TCP鏈接握手爲啥是三次而不是二次或者四次呢?

原理:在不可靠信道上可靠地傳輸信息.
可靠消息傳輸是基於咱們的ack:確認號實現的,假如咱們採用2次握手,client端發送創建鏈接請求後,server端收到消息以後,發送確認收到消息以後就分配資源等待client端發送數據,會存在在不可靠的網絡通道下,client端發送了數據包A而後又發送了數據包B,因爲網絡緣由,後發送的數據包B先到達,而後server端收到數據包以後給其分配資源,準備接收數據,此時client跟server端就正常發送數據。可是因爲後面達到的數據包A又到達創建鏈接,此時server端就會再次分配資源。可是此時client端已經能夠正常發送數據,已經進入了鏈接創建狀態因此再也不理會server端的資源分配,這樣的話,在信道不可靠的狀況下,多個請求發送時候會建立大量鏈接請求,服務端資源浪費。由於3次握手已經能夠創建鏈接了不須要4次。

延伸:三次握手不是TCP自己的要求, 而是爲了知足"在不可靠信道上可靠地傳輸信息"這一需求所致使的. 請注意這裏的本質需求,信道不可靠, 數據傳輸要可靠. 三次達到了, 那後面你想接着握手也好, 發數據也好, 跟進行可靠信息傳輸的需求就不要緊了. 所以,若是信道是可靠的, 即不管何時發出消息, 對方必定能收到, 或者你不關心是否要保證對方收到你的消息, 那就能像UDP那樣直接發送消息就能夠了。

三、爲何TCP鏈接斷開是4次分手,而不是3次或者5次?

TCP的4次揮手爲了保證資源的準確釋放,前兩次分手是確保client端發送的釋放請求被服務端接收到,後兩次分手是爲了server確保本身資源釋放請求client端已經收到。可是關閉鏈接時,當Server端收到FIN報文時,極可能並不會當即關閉SOCKET,因此只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端全部的報文都發送完了,我才能發送FIN報文,所以不能一塊兒發送。故須要四步握手。

爲何不是3次:由於服務端資源釋放是有一個相對的過程,若是3次分手就關閉關聯的話,應用程序可能尚未收到鏈接關閉請求。

四、爲何TIME_WAIT狀態須要通過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?

雖然按道理,四個報文都發送完畢,咱們能夠直接進入CLOSE狀態了,可是咱們必須假象網絡是不可靠的,有能夠最後一個ACK丟失。因此TIME_WAIT狀態就是用來重發可能丟失的ACK報文。在Client發送出最後的ACK回覆,但該ACK可能丟失。Server若是沒有收到ACK,將不斷重複發送FIN片斷。因此Client不能當即關閉,它必須確認Server接收到了該ACK。Client會在發送出ACK以後進入到TIME_WAIT狀態。Client會設置一個計時器,等待2MSL的時間。若是在該時間內再次收到FIN,那麼Client會重發ACK並再次等待2MSL。所謂的2MSL是兩倍的MSL(Maximum Segment Lifetime)。MSL指一個片斷在網絡中最大的存活時間,2MSL就是一個發送和一個回覆所需的最大時間。若是直到2MSL,Client都沒有再次收到FIN,那麼Client推斷ACK已經被成功接收,則結束TCP鏈接。

五、若是已經創建了鏈接,可是客戶端忽然出現故障了怎麼辦?

TCP設有一個保活計時器,客戶端若是出現故障,服務器不能一直等下去白白浪費資源。服務器每收到一次客戶端的請求後都會從新復位這個計時器,時間一般是設置爲2小時,若兩小時尚未收到客戶端的任何數據,服務器就會發送一個探測報文段,之後每隔75秒鐘發送一次。若一連發送10個探測報文仍然沒反應,服務器就認爲客戶端出了故障,接着就關閉鏈接。

六、TCP連接數據包到達順序如何保證?

image.png

網絡數據包是不必定先發先到,可是對於TCP有一點特殊,若咱們接受的數據包是在應用層,而且應用層用的是TCP的傳輸協議的話,這個順序是保證,這個順序的保證是在傳輸層保證的:

client發生數據A,B給server,使用的TCP傳輸,client發送毫無疑問是先發送A,而後發送B,雖然A跟B在物理層走的鏈路不同,傳輸速度不同,B是會比A先到達Server,這個是沒有錯的,可是這個數據包被接受是在網絡層跟傳輸層。網絡跟傳輸層的做用,網絡層是保證同一個包的完整,若是傳輸層發出的包過大,在網絡層(也就是IP層)會被分包;同時在Sever的網絡接受的時候會被組包,有一個完整的包纔會交給傳輸層,若包不完整是會丟棄,同時他也不保證你的包的是否達到,數據包的保證是在傳輸層作的,就是說若傳輸層(TCP協議纔會,UDP並不保證)沒有收到對方的確認包,會有超時重傳,每一個數據包也是有序列號的,同時,傳輸層就是根據這個序列號來保證A,B包的順序,即便B比A先到達了,TCP也會是等A到達以後,先把A提交給應用層,再把B的數據提交給應用層,從而保證了,同一條TCP連接,先發的包先到.

參考

https://blog.csdn.net/lengxia...

相關文章
相關標籤/搜索