天天看點

就是要你懂TCP -- 握手和揮手就是要你懂 TCP -- 握手和揮手

tcp的特點大家基本都能說幾句,面試的時候候選人也肯定會告訴你這些:

三次握手

四次揮手

可靠連接配接

丢包重傳

但是我隻希望大家記住一個核心的:tcp是可以可靠傳輸協定,它的所有特點都為這個可靠傳輸服務。

tcp在傳輸過程中都有一個ack,接收方通過ack告訴發送方收到那些包了。這樣發送方能知道有沒有丢包,進而确定重傳

來看一個java代碼連接配接資料庫的三次握手過程

就是要你懂TCP -- 握手和揮手就是要你懂 TCP -- 握手和揮手

三個紅框表示建立連接配接的三次握手:

第一步:client 發送 syn 到server 發起握手;

第二步:server 收到 syn後回複syn+ack給client;

第三步:client 收到syn+ack後,回複server一個ack表示收到了server的syn+ack(此時client的48287端口的連接配接已經是established)

握手的核心目的是告知對方seq(綠框是client的初始seq,藍色框是server 的初始seq),對方回複ack(收到的seq+包的大小),這樣發送端就知道有沒有丢包了

握手的次要目的是告知和協商一些資訊,圖中黃框。

mss--最大傳輸包

sack_perm--是否支援selective ack(使用者優化重傳效率)

ws--視窗計算指數(有點複雜的話先不用管)

這就是tcp為什麼要握手建立連接配接,就是為了解決tcp的可靠傳輸

再來看java連上mysql後,執行了一個sql: select sleep(2); 然後就斷開了連接配接

就是要你懂TCP -- 握手和揮手就是要你懂 TCP -- 握手和揮手

四個紅框表示斷開連接配接的四次揮手:

第一步: client主動發送fin包給server

第二步: server回複ack(對應第一步fin包的ack)給client,表示server知道client要斷開了

第三步: server發送fin包給client,表示server也可以斷開了

第四部: client回複ack給server,表示既然雙發都發送fin包表示斷開,那麼就真的斷開吧

這個問題太惡心,面試官太喜歡問,其實他也許隻能背誦:因為……。

我也不知道怎麼回答。網上都說tcp是雙向的,是以斷開要四次。但是我認為建連接配接也是雙向的(雙向都協調告知對方自己的seq号),為什麼不需要四次握手呢,是以網上說的不一定精準。

你再看三次握手的第二步發 syn+ack,如果拆分成兩步先發ack再發syn完全也是可以的(效率略低),這樣三次握手也變成四次握手了。

看起來揮手的時候多一次,主要是收到第一個fin包後單獨回複了一個ack包,如果能回複fin+ack那麼四次揮手也就變成三次了。 來看一個案例:

就是要你懂TCP -- 握手和揮手就是要你懂 TCP -- 握手和揮手

圖中第二個紅框就是回複的fin+ack,這樣四次揮手變成三次了(如果一個包就是一次的話)。

我的了解:之是以絕大數時候我們看到的都是四次揮手,是因為收到fin後,知道對方要關閉了,然後os通知應用層要關閉啥的,這裡應用層可能需要做些準備工作,有一些延時,是以先回ack,準備好了再發fin 。 握手過程沒有這個準備過程是以可以立即發送syn+ack

ack總是seq+len(包的大小),這樣發送方明确知道server收到那些東西了

但是特例是三次握手和四次揮手,雖然len都是0,但是syn和fin都要占用一個seq号,是以這裡的ack都是seq+1

就是要你懂TCP -- 握手和揮手就是要你懂 TCP -- 握手和揮手

看圖中左邊紅框裡的len+seq就是接收方回複的ack的數字,表示這個包接收方收到了。然後下一個包的seq就是前一個包的len+seq,依次增加,一旦中間發出去的東西沒有收到ack就是丢包了,過一段時間(或者其他方式)觸發重傳,保障了tcp傳輸的可靠性。

mss 最大一個包中能傳輸的資訊(不含tcp、ip標頭),mss+標頭就是mtu(最大傳輸單元),如果mtu過大可能在傳輸的過程中被卡住過不去造成卡死(這個大小的包一直傳輸不過去),跟丢包還不一樣

sack_perm 用于丢包的話提升重傳效率,比如client一次發了1、2、3、4、5 這5個包給server,實際server收到了 1、3、4、5這四個包,中間2丢掉了。這個時候server回複ack的時候,都隻能回複2,表示2前面所有的包都收到了,給我發第二個包吧,如果server 收到3、4、5還是沒有收到2的話,也是回複ack 2而不是回複ack 3、4、5、6的,表示快點發2過來。

但是這個時候client雖然知道2丢了,然後會重發2,但是不知道3、4、5有沒有丢啊,實際3、4、5 server都收到了,如果支援sack,那麼可以ack 2的時候同時告訴client 3、4、5都收到了,這樣client重傳的時候隻重傳2就可以,如果沒有sack的話那麼可能會重傳2、3、4、5,這樣效率就低了。

來看一個例子:

就是要你懂TCP -- 握手和揮手就是要你懂 TCP -- 握手和揮手

圖中的紅框就是sack。

知識點:ack數字表示這個數字前面的資料都收到了

tcp所有特性基本上核心都是為了可靠傳輸這個目标來服務的,然後有一些是出于優化性能的目的

後續希望再通過幾個案例來深化一下上面的知識。

我的其他幾篇跟網絡問題相關的文章,也很有趣,借着案例來了解好概念和原理,希望對大家也有點幫助

<a href="https://www.atatech.org/articles/80573">網絡通不通這是個麻煩的大問題 -- 一個網絡包的旅程</a>

<a href="https://www.atatech.org/articles/73289">https://www.atatech.org/articles/73289</a>

<a href="https://www.atatech.org/articles/76138">https://www.atatech.org/articles/76138</a>

<a href="https://www.atatech.org/articles/60633">https://www.atatech.org/articles/60633</a>

<a href="https://www.atatech.org/articles/73174">https://www.atatech.org/articles/73174</a>

說點關于學習的題外話

有些人純看理論就能掌握好一門技能,還能舉一反三,這是知識效率,這種人非常少;

大多數普通人都是看點知識然後結合實踐來強化理論,要經過反反複複才能比較好地掌握一個知識,這就是工程效率,講究技巧、工具來達到目的。

肯定知識效率最牛逼,但是擁有這種技能的人畢竟非常少。從小我們周邊那種不怎麼學的學霸型基本都是這類,這種學霸都還能觸類旁通非常快的掌握一個新知識,非常氣人。剩下的絕大部分隻能拼時間+方法+總結等也能掌握一些知識

非常遺憾我就是工程效率型,隻能羨慕那些知識效率型的學霸。但是這事又不能獨立看待有些人在某些方向上是工程效率型,有些方向就又是知識效率型(有一種知識效率型是你掌握的實在太多也就比較容易觸類旁通了,這算灰色知識效率型)

使勁挖掘自己在知識效率型方面的能力吧,即使灰色地帶也行啊

繼續閱讀