TCP 三次握手的意義

概述

在網絡的傳輸層協議中, 存在着兩大悍將: TCPUDP . 從前, 我傻傻的以爲自己對他們雖談不上精通, 但還是知道的, 但是, 我錯了, 我被自己問住了, 我傻了. 啥也不是.

UDP

(這裏爲了介紹簡單, 就不提數據在傳輸過程中的失真(糾錯碼)等情況了. 簡單介紹一下, TCP纔是今天的主角)

UDP 就是, 我把數據發給你了, 我不管你有沒有收到, 反正我發出去了, 任性. 就比如我要給我的女神表白, 但是我又不好意思, 所以我託我的好兄弟馬六幫我給女神帶句話, 但是這個馬六也臉皮薄, 他又找週三轉達, 就這樣雖然歷經波折, 但最後還是順利的將話帶到了女神那裏. 在這個過程中我做了什麼? 我只是將消息送出去了, 僅此而已. 最後我滿心歡喜的等待着女神的回覆, 可能換回一句: 我們還是做朋友吧. 但還有一種可能, 那就是最終根本就沒有送到女神那裏, 中間轉到週三的時候, 他因爲自己的事情, 把這事給忘了, 可憐的我還苦苦的等...

UDP 雖然省事, 高效, 但是卻不可靠. 因爲我僅僅是發出去了, 但是我不確定你有沒有收到. 不可靠有什麼問題麼? 上面就是個例子. 再比如, 咱倆聊天, 我給你發了一段話: 123456, 結果中間4丟了, 你收到的信息是: 12356. 這種還好, 如果快過年了, 我發給你這樣一段話: 明天把你的豬宰了吧, 哎, 中間 的豬 丟了, 那估計免不了一番腥風血雨.

那如此不可靠的UDP協議, 有什麼用呢? 還真有, 雖然不可靠, 但是他快啊. 在一些對數據的可靠性要求不高, 但是實時性很強的地方就有了用武之地, 比如視頻電話(我也不知道底層是不是 UDP, 舉個例子), 打視頻電話的時候, 視頻要保證其連續性, 而且中間如果丟了一幀也不會有什麼影響.

但是在大多數場景下, 數據的可靠性還是要有保證的, 你從網上下載一個程序的安裝包, 如果中間丟了一個字節的數據, 那可能就導致一個200mb 的文件廢了, 根本不能執行.

TCP

爲了保證傳輸數據的可靠性, TCP 誕生了. 還記得剛纔我給女神表白的時候, 問題出在哪裏嗎? 沒錯, 就是因爲我到最後苦苦等待, 結果她悲劇的沒有收到我的心意, 傷心. 怎麼辦呢? 這次我想通了, 求人不如求己, 我要鼓起勇氣, 我到她面前當面告訴她, 即使我多了一個朋友(沒辦法, 咱就喜歡交朋友), 也好過她收不到消息的好. 這下可靠了, 我確信她收到了.

區別在哪裏? 不是我到他面前, 而是不管她是否願意, 至少給爺們回句話吧. 沒錯, 就是回句話.

image-20200612230118536

如果有這樣一種機制, 每次我發出去的數據, 如果對方收到了, 就給我回句話, 告訴我收到了, 那消息就變得可靠了. 我發出去的所有消息, 都可以確信對方已經收到了.

  • 如果數據中間丟了, 對方沒有收到怎麼辦? 沒有等到對方回覆, 我就重新發一遍就好啦.
  • 如果對方的回覆丟了, 沒有收到回覆怎麼辦? 處理方式同上, 對方收到重複數據, 把重複的數據包丟棄再回復一條就好啦.

一個來自靈魂的提問, 現在的數據發送可靠嗎? 我覺得是不可靠的, 現在僅僅能夠保證一個數據包, 我百分百的確信對方已經收到了. 那什麼樣的連接纔是可靠的呢?

我要發你100個數據包, 那這100個數據包你每一個都要能夠收到, 並且要按照順序將他們再拼裝起來, 我覺得這樣的連接才能稱得上可靠. 這裏面涉及到了兩個概念, 確保收到順序. 確保收到我們已經做到了, 如何保證包的順序呢? 我把要發的數據排排隊, 一個一個發就行了? 天真, 如果有包1在網絡中某個地方喝了杯茶, 睡了一覺, 結果接收方先收到了包2後收到包1, 順序就亂了. 保證順序的方式其實很簡單, 在每一個包上, 都加上一個序號, 接收方按照序號從小到大把收到的包組裝起來就好了.

經過改造, 現在已經基本能夠保證傳輸的可靠性了, 到這裏, 有沒有發現什麼? 現在和TCP的區別就是少了三次握手四次揮手(不僅僅是). 那三次握手的意義何在?

三次握手意義何在

今天在接收了身邊大神的一些思想之後, 我還是沒有太明白. 不過現在, 我貌似明白了些什麼. 要想知道三次握手有什麼用, 就需要知道三次握手都做了什麼事情.

1. 確保對方能夠正常接收數據, 測試連接

還是上面的例子, 我去女神面前表白, 但不湊巧, 女神正在午休, 我站着旁邊傻傻的表白, 還是沒有用. 所以, 在開始之前, 我要先確保女神能夠聽到我說的話, 我得把她叫醒, 莊重的告訴她. 而這, 就是握手的意義.

2.建立系統開銷

在發送 UDP 包的時候, 因爲其不可靠性, 所以基本不會用其發送很大的文件, 因爲將較大的數據拆分後發出, 中間丟了幾個數據包就尷尬了. 而且 UDP 也不能夠保證包的順序, 還是一樣的原因. 但是 TCP 就不一樣了, 它是可靠的啊, 你可以將多個數據包分開發給我, 到我這裏, 我再把他們按順序排列好就行了. 而這個按順序排列的操作就需要專門開闢內存空間來保存收到的數據包了, 當握手成功後, 我就會爲你留下用於保存數據包的內存空間及其他一些系統資源.

而如果沒有三次握手呢? 客戶端發送的數據包, 可能因爲某些原因(比如路不好走), 在網絡中待的久了一些, 客戶端因爲沒有收到回覆, 已經放棄連接了, 但這時候, 服務器收到了這個數據包, 開闢系統資源, 返回確認包, 然後就沒有然後了. 客戶端已經放棄了, 根本不搭理你的回覆. 系統的相關資源就白白浪費了.

3. 測試超時時間

上面說了, 當我長時間沒有收到你的回覆時, 我就認爲你沒有收到我發出的數據, 那我就需要重新發送了. 那這個長時間是多久呢? 可以在握手期間進行測試, 測量請求包的往返時間,並依此計算重傳的超時時間.

4.安全性

這個確實是我沒有想到的. 因爲 TCP 會將數據拆分後發送, 爲了保證數據的有序, 就要給每個數據包進行編號. 然後接收方根據編號的順序對收到的包進行重組, 保證了數據的有序.

如果只是簡單的123456, 那大家都知道了, 我黑客小黑, 也給你發一個編號爲1的數據包, 不就把你真實的數據包給偷偷替換了麼? 爲了防止序列號被猜到, 就要讓每次發送數據的序列號不同, 在進行握手的時候會對數據的初始序列號進行交換. 客戶端第一次發送握手信息的時候, 會連着自己的初始序列號一起發過去, 服務器收到之後, 返回第二個握手信息的時候, 除了返回握手確認, 也會連着自己的初始序列號一起發回來. 這在一定程度上保證了數據的安全傳輸. 當然這種防護措施很弱.

這個隨機的序列號其實還有另外一個作用, 我覺得這纔是它最主要的作用. 如果我們上一次連接的其中一個數據包3, 在網絡中傲遊了一會, 連接已經斷開了, 我們又開始了新的一次數據連接, 這個時候我收到了數據包3, 就會導致生成了錯誤的數據序列, 而隨機序列號則避免了這個問題,

四次揮手的意義

三次握手確實是有些作用, 那四次揮手有什麼用呢?

1.釋放系統資源

在三次握手的時候, 爲了接收數據並進行序列重組, 開闢了一些系統資源, 當數據發送完了, 就不用一直佔着了, 早些釋放, 留給別人.

額, 應該還有其他作用吧...

總結

綜上, 你說如果沒有握手揮手的過程, 能不能實現一個可靠的連接呢? 可以, 只不過會有問題. 個人簡單將握手的作用總結爲以下幾點:

  1. 爲了對數據進行順序重組, 勢必需要開闢系統資源. 如果沒有握手的過程, 所有的請求, 都要佔用資源. 而沒有揮手的過程, 這些資源就不能及時釋放.
  2. 爲了數據的高效傳輸, 選用一個合理的超時重傳時間是十分有必要的. 時間短了, 會導致頻繁重傳, 浪費網絡資源. 時間長了, 就會導致整體的數據傳輸時間變長.
  3. 爲了保證對方能夠正常接收數據, 否則對方關機了, 我總不能在這一直超時重傳吧.
  4. 爲了保證多次連接的數據包不會引發數據錯誤. 通過隨機的序列號, 保證了兩次連接的數據包不會互相影響.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章