一、TCP的三次握手

首先來通俗的解釋一下TCP的三次握手:

假設A和B是通過簡訊進行聯繫的

第一次(握手)對話:

中午12點,A給B發簡訊說:「走,去食堂喫飯」。 如果此時B沒帶手機沒有接受到簡訊,那肯定是對話失敗的,A等了一會B沒回他的簡訊,他就會自己去喫飯,肯定不會一直等到下午吧。

這說明B沒有接受到A的消息時溝通是肯定失敗的。

如果B看到A發的消息則說明第一次對話成功。接下來進行第二次對話。

第二次(握手)對話:

B收到並且看到了A發來的消息,但是B是個外國人,他的中文不太好不能理解A所發簡訊的意思,於是隨便回了一句學會的中文:」我愛你「。

A收到之後菊花一緊,心想我只是想和你一起喫飯,你卻。。。。 這該死的基佬。告辭。於是溝通失敗。因為B無法根據A的消息做出正確的應答。

如果B的中文足夠好,他看懂了A的消息,並回了一句:」好,那我去老地方等你「,那麼第二次握手成功。

通過前兩次對話證明瞭B能夠聽懂說的話,並且能做出正確的應答。 接下來進行第三次對話。

第三次( 握手)對話:

A看到B發的消息:「好,那我去老地方等你」,但是A的媽媽喊他現在立刻馬上回家喫飯,A是個聽媽媽話的孩子,於是立馬回家喫飯了。然後B就等一大半天沒看到A回消息就想:怎麼還不回我消息,到底去不起啊?不去算鳥。

於是溝通失敗,這是因為A無法對B的消息做出正確的應答。

但是如果A看到B發的消息後回復到:「好的,我馬上過來」。那麼第三次對話成功,兩個人就可以開心的一起去喫飯了,並繼續聊天啥的進行後續活動。

通過第二次和第三次的對話證明瞭甲能夠聽懂乙說的話,並且能做出正確的應答。

可見,兩個人進行有效的語言溝通,這三次對話的過程是必須的。

為了保證服務端能收接受到客戶端的信息並能做出正確的應答而進行前兩次(第一次和第二次)握手,為了保證客戶端能夠接收到服務端的信息並能做出正確的應答而進行後兩次(第二次和第三次)握手。

TCP連接的建立採用客戶伺服器方式。主動發起連接建立的應用進程叫做客戶,而被動等待連接建立的應用進程叫做伺服器

在這個例子中A是客戶,B是伺服器。

再來看一個問題:為什麼要進行三次握手而不是兩次呢?

然後看一個我覺得比較好的解釋:

在Google Groups的TopLanguage中看到一帖討論TCP「三次握手」覺得很有意思。貼主提出「TCP建立連接為什麼是三次握手?」的問題,在眾多回復中,有一條回複寫道:「這個問題的本質是, 信道不可靠, 但是通信雙發需要就某個問題達成一致. 而要解決這個問題, 無論你在消息中包含什麼信息, 三次通信是理論上的最小值. 所以三次握手不是TCP本身的要求, 而是為了滿足"在不可靠信道上可靠地傳輸信息"這一需求所導致的. 請注意這裡的本質需求,信道不可靠, 數據傳輸要可靠. 三次達到了, 那後面你想接著握手也好, 發數據也好, 跟進行可靠信息傳輸的需求就沒關係了. 因此,如果信道是可靠的, 即無論什麼時候發出消息, 對方一定能收到, 或者你不關心是否要保證對方收到你的消息, 那就能像UDP那樣直接發送消息就可以了.」。這可視為對「三次握手」目的的另一種解答思路。

然後說一下我自己的理解

因為TCP是面向連接的運輸層協議,在應用程序使用TCP協議之前,必須先建立TCP連接。在傳輸數據完畢後,必須釋放已經建立的TCP連接。並且TCP提供的是可靠交付的服務。且TCP提供全雙工通信。

所以要進行三次握手來確保在不可靠信道上可靠的傳輸信息。至於為什麼進行三次握手前面已經給出了一個解釋的角度。

再結合上面的例子解釋一下:

首先從這個角度理解: 三次通信是理論上在不可靠信道上進行可靠通信的最小值.

如果只進行兩次握手,即A和B說:「走,去食堂喫飯」。B回復到:「好,那我去老地方等你」。如果這兩次就算成功溝通了,那麼如果A讀不懂B的意思,或者A發生緊急事件(媽媽喊他回家喫飯),那就只剩B一個人去老地方等A等一大半天A都不來,然而B是一個守信用的人,心想:說好和A一起到老地方喫飯的A不來我就不喫。。。。於是這就浪費了B大把的時間。

在從另一個角度理解:這主要是為了防止已經失效的連接請求報文突然又傳送到了B,因而產生了錯誤。

比如說,A中午12點給B發消息:「走,去食堂喫飯」。但是消息滯後了6個小時(現實情況基本不會發生 ,這裡假設發生了這種情況),A第一次發的消息滯後了所以A沒有收到回復就又重新發了一條, 此時B收到了第二條消息建立正確連接一起去喫中飯了。然後到了下午,A中午發的滯後了6個小時的第一條消息(相當於已失效的請求報文段)傳到B的手機裏(已經是下午6點),如果只進行兩次握手的話,B回復了:「好,那我去老地方等你」。這時A收到這條消息心想我沒有約你喫飯啊,就沒有理他。。B就去食堂等A喫晚飯了。於是又留B在食堂苦等。。浪費時間。。B真可憐。。。

事情大概就是這麼個事情,可能不太合理,不過是我理解的比較好的故事了叭。。。

故事終於講完了,然後再來看看TCP的連接時如何建立的

(沒錯我還是謝希仁的圖)

要想理解這個圖首先。。首先得理解那幾個字母叭。。SYN,seq,ACK,ack是啥子東西啊?。。。

於是咱們就得看看TCP報文段的首部格式了

(emmmm...我也是謝希仁...以後就不再進行說明瞭)

暫時需要的信息有:

emmm....下面知道了那幾個字母啥子意思我們再來看三次握手

把圖再放一遍免得上下翻。。。

  • 最初兩端的TCP進程都處於CLOSE(關閉)狀態。上圖中A主動打開連接,B被動打開連接。
  • B打開連接後處於LISTEN(監聽狀態),等待客戶的連接請求。
  • A向B發送請求報文,SYN=1,ACK=0,選擇一個初始序號seq=x。
  • B 收到連接請求報文,如果同意建立連接,則向 A 發送連接確認報文,SYN=1,ACK=1,確認號為ack= x+1,同時也選擇一個初始的序號 seq=y。
  • A 收到 B 的連接確認報文後,還要向 B 發出確認,確認號為ack= y+1,序號為 seq=x+1。
  • B 收到 A 的確認後,連接建立。

TCP的三次握手事情就是這麼個事情。(如有錯誤,還望指正)下面來看看TCP的四次揮手。

二、TCP的四次揮手

數據傳輸結束後,通信的雙方都可釋放連接。

此處為A的應用進程先向其TCP發出連接釋放報文段,但是A結束TCP連接的時間要比B晚一些。

以下描述不討論序號和確認號,因為序號和確認號的規則比較簡單。並且不討論 ACK,因為 ACK 在連接建立之後都為 1。

  • A 發送連接釋放報文,FIN=1。
  • B 收到之後發出確認,此時 TCP 屬於半關閉狀態,B 能向 A 發送數據但是 A 不能向 B 發送數據。
  • 當 B 不再需要連接時,發送連接釋放報文,FIN=1。
  • A 收到後發出確認,進入 TIME-WAIT 狀態,等待 2 MSL(最大報文存活時間)後釋放連接。
  • B 收到 A 的確認後釋放連接。

四次揮手的原因

CLOSE-WAIT

客戶端發送了 FIN 連接釋放報文之後,伺服器收到了這個報文,就進入了 CLOSE-WAIT 狀態。這個狀態是為了讓伺服器端發送還未傳送完畢的數據,傳送完畢之後,伺服器會發送 FIN 連接釋放報文。

TIME-WAIT

客戶端接收到伺服器端的 FIN 報文後進入此狀態,此時並不是直接進入 CLOSED 狀態,還需要等待一個時間計時器設置的時間 2MSL。

為什麼A在TIME-WAIT狀態必須等待2MSL的時間呢?

這麼做有兩個理由:

  • 為了保證A發送的最後一個ACK報文段能夠到達B。A發送的這個ACK報文段有可能丟失,如果 B 沒收到 A 發送來的確認報文,那麼A就會重新發送連接釋放請求報文,A 等待一段時間就是為了處理這種情況的發生。
  • 防止「已經失效的連接請求報文段」出現在本鏈接中。A在發送完最後一個ACK報文段後,再經過時間2MSL,就可以使本連接的時間內所產生的所有報文段都從網路中消失。這樣下一個新的連接中就不會出現這種舊的連接請求報文段。

為什麼建立連接協議是三次握手,而關閉連接卻是四次握手呢?

這是因為服務端的LISTEN狀態下的SOCKET當收到SYN報文的連接請求後,它可以把ACK和SYN(ACK起應答作用,而SYN起同步作用)放在一個報文裏來發送。但關閉連接時,當收到對方的FIN報文通知時,它僅僅表示對方沒有數據發送給你了;但未必你所有的數據都全部發送給對方了,所以你可能未必會馬上會關閉SOCKET,也即你可能還需要發送一些數據給對方之後,再發送FIN報文給對方來表示你同意現在可以關閉連接了,所以它這裡的ACK報文和FIN報文多數情況下都是分開發送的。

(如有錯誤,還望指正)。

參考文章:

《計算機網路(第七版)》謝希仁

通俗大白話來理解TCP協議的三次握手和四次分手

CYC2018_計算機網路

推薦閱讀:

相關文章