「三次握手,四次揮手」你真的懂嗎?

記得剛畢業找工做面試的時候,常常會被問到:你知道「3次握手,4次揮手」嗎?這時候我會「成竹在胸」地「背誦」前期準備好的「答案」,第一次怎麼怎麼,第二次……答完就沒有下文了,面試官貌似也沒有深刻下去的意思,深刻下去我也不懂,皆大歡喜!程序員

做爲程序員,要有「刨根問底」的精神。知其然,更要知其因此然。這篇文章但願能抽絲剝繭,還原背後的原理。面試

什麼是「3次握手,4次揮手」服務器

TCP是一種面向鏈接的單播協議,在發送數據前,通訊雙方必須在彼此間創建一條鏈接。所謂的「鏈接」,實際上是客戶端和服務器的內存裏保存的一份關於對方的信息,如ip地址、端口號等。網絡

TCP能夠當作是一種字節流,它會處理IP層或如下的層的丟包、重複以及錯誤問題。在鏈接的創建過程當中,雙方須要交換一些鏈接的參數。這些參數能夠放在TCP頭部。tcp

TCP提供了一種可靠、面向鏈接、字節流、傳輸層的服務,採用三次握手創建一個鏈接。採用4次揮手來關閉一個鏈接。進程

TCP服務模型ip

在瞭解了創建鏈接、關閉鏈接的「三次握手和四次揮手」後,咱們再來看下TCP相關的東西。內存

一個TCP鏈接由一個4元組構成,分別是兩個IP地址和兩個端口號。一個TCP鏈接一般分爲三個階段:啓動、數據傳輸、退出(關閉)。原理

當TCP接收到另外一端的數據時,它會發送一個確認,但這個確認不會當即發送,通常會延遲一下子。ACK是累積的,一個確認字節號N的ACK表示全部直到N的字節(不包括N)已經成功被接收了。這樣的好處是若是一個ACK丟失,極可能後續的ACK就足以確認前面的報文段了。請求

一個完整的TCP鏈接是雙向和對稱的,數據能夠在兩個方向上平等地流動。給上層應用程序提供一種雙工服務。一旦創建了一個鏈接,這個鏈接的一個方向上的每一個TCP報文段都包含了相反方向上的報文段的一個ACK。

序列號的做用是使得一個TCP接收端可丟棄重複的報文段,記錄以雜亂次序到達的報文段。由於TCP使用IP來傳輸報文段,而IP不提供重複消除或者保證次序正確的功能。另外一方面,TCP是一個字節流協議,毫不會以雜亂的次序給上層程序發送數據。所以TCP接收端會被迫先保持大序列號的數據不交給應用程序,直到缺失的小序列號的報文段被填滿。

TCP頭部

tcp header

源端口和目的端口在TCP層肯定雙方進程,序列號表示的是報文段數據中的第一個字節號,ACK表示確認號,該確認號的發送方期待接收的下一個序列號,即最後被成功接收的數據字節序列號加1,這個字段只有在ACK位被啓用的時候纔有效。

當新建一個鏈接時,從客戶端發送到服務端的第一個報文段的SYN位被啓用,這稱爲SYN報文段,這時序列號字段包含了在本次鏈接的這個方向上要使用的第一個序列號,即初始序列號ISN,以後發送的數據是ISN加1,所以SYN位字段會消耗一個序列號,這意味着使用重傳進行可靠傳輸。而不消耗序列號的ACK則不是。

頭部長度(圖中的數據偏移)以32位字爲單位,也就是以4bytes爲單位,它只有4位,最大爲15,所以頭部最大長度爲60字節,而其最小爲5,也就是頭部最小爲20字節(可變選項爲空)。

ACK —— 確認,使得確認號有效。
RST —— 重置鏈接(常常看到的reset by peer)就是此字段搞的鬼。
SYN —— 用於初如化一個鏈接的序列號。
FIN —— 該報文段的發送方已經結束向對方發送數據。

當一個鏈接被創建或被終止時,交換的報文段只包含TCP頭部,而沒有數據。

狀態轉換

三次握手和四次揮手的狀態轉換以下圖。
tcp connect

爲何要「三次握手,四次揮手」

三次握手

換個易於理解的視角來看爲何要3次握手。

客戶端和服務端通訊前要進行鏈接,「3次握手」的做用就是雙方都能明確本身和對方的收、發能力是正常的。

第一次握手:客戶端發送網絡包,服務端收到了。這樣服務端就能得出結論:客戶端的發送能力、服務端的接收能力是正常的。

第二次握手:服務端發包,客戶端收到了。這樣客戶端就能得出結論:服務端的接收、發送能力,客戶端的接收、發送能力是正常的。
從客戶端的視角來看,我接到了服務端發送過來的響應數據包,說明服務端接收到了我在第一次握手時發送的網絡包,而且成功發送了響應數據包,這就說明,服務端的接收、發送能力正常。而另外一方面,我收到了服務端的響應數據包,說明我第一次發送的網絡包成功到達服務端,這樣,我本身的發送和接收能力也是正常的。

第三次握手:客戶端發包,服務端收到了。這樣服務端就能得出結論:客戶端的接收、發送能力,服務端的發送、接收能力是正常的。
第1、二次握手後,服務端並不知道客戶端的接收能力以及本身的發送能力是否正常。而在第三次握手時,服務端收到了客戶端對第二次握手做的迴應。從服務端的角度,我在第二次握手時的響應數據發送出去了,客戶端接收到了。因此,個人發送能力是正常的。而客戶端的接收能力也是正常的。

經歷了上面的三次握手過程,客戶端和服務端都確認了本身的接收、發送能力是正常的。以後就能夠正常通訊了。

每次都是接收到數據包的一方能夠獲得一些結論,發送的一方其實沒有任何頭緒。我雖然有發包的動做,可是我怎麼知道我有沒有發出去,而對方有沒有接收到呢?

而從上面的過程能夠看到,最少是須要三次握手過程的。兩次達不到讓雙方都得出本身、對方的接收、發送能力都正常的結論。其實每次收到網絡包的一方至少是能夠獲得:對方的發送、我方的接收是正常的。而每一步都是有關聯的,下一次的「響應」是因爲第一次的「請求」觸發,所以每次握手實際上是能夠獲得額外的結論的。好比第三次握手時,服務端收到數據包,代表看服務端只能獲得客戶端的發送能力、服務端的接收能力是正常的,可是結合第二次,說明服務端在第二次發送的響應包,客戶端接收到了,而且做出了響應,從而獲得額外的結論:客戶端的接收、服務端的發送是正常的。

用表格總結一下:

視角 客收 客發 服收 服發
客視角 二 一 + 二 一 + 二 二
服視角 二 + 三 一 一 二 + 三
四次揮手

TCP鏈接是雙向傳輸的對等的模式,就是說雙方均可以同時向對方發送或接收數據。當有一方要關閉鏈接時,會發送指令告知對方,我要關閉鏈接了。這時對方會回一個ACK,此時一個方向的鏈接關閉。可是另外一個方向仍然能夠繼續傳輸數據,等到發送完了全部的數據後,會發送一個FIN段來關閉此方向上的鏈接。接收方發送ACK確認關閉鏈接。注意,接收到FIN報文的一方只能回覆一個ACK, 它是沒法立刻返回對方一個FIN報文段的,由於結束數據傳輸的「指令」是上層應用層給出的,我只是一個「搬運工」,我沒法瞭解「上層的意志」。

「三次握手,四次揮手」怎麼完成?

其實3次握手的目的並不僅是讓通訊雙方都瞭解到一個鏈接正在創建,還在於利用數據包的選項來傳輸特殊的信息,交換初始序列號ISN。

3次握手是指發送了3個報文段,4次揮手是指發送了4個報文段。注意,SYN和FIN段都是會利用重傳進行可靠傳輸的。

三次握手

相關文章
相關標籤/搜索