日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

协议簇:TCP 解析: 建立连接

發布時間:2024/7/23 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 协议簇:TCP 解析: 建立连接 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

簡介

接前文 協議簇:TCP 解析: 基礎, 我們這篇文章來看看 TCP 連接建立的過程,也就是眾所周知的”三次握手“的具體流程.

系列文章

協議簇:TCP 解析:基礎
協議簇:TCP 解析:建立連接
協議簇:TCP 解析:連接斷開
協議簇:TCP 解析:Sequence Number
協議簇:TCP 解析:數據傳輸

三次握手

最普通的 TCP 握手流程如下圖:

下面描述中,序列號對應于上圖中的行號.

  • 初始狀態時,TCP A 處于連接關閉狀態, TCP B 處于監聽狀態. 也就是通常所說的 A 時 TCP 客戶段,B 是服務端.
  • A 發送 SYN 給 B, 并附有 SEQ, 請求建立 TCP 連接。
    A 發送 SYN 后,狀態切換為 SYN-SENT, B 接收到 A 發送的 SYN 后狀態切換為 SYN-RECEIVED.
  • B 收到 A 的 SYN 之后,發送它的 SYN(注意,這里 A 和 B 的 SEQ 是相互獨立的 ),并附上 ACK 標記用以表明 B 收到了 A 的 SYN 包。
    這里注意: B 發送的 ACK 的值為 101,它代表 B 收到了序列號為 100和100之前的所有字節數據,并告訴 A 自己期待下一次收到序列號以101開始的數據.
    A 在接收到 B 的 SYN 之后,狀態轉化為 ESTABLISHED.
  • A 收到 B 的 SYN 之后, 需要發送 ACK 給 B 告訴 B 自己收到了它的 SYN + ACK 包.
    這里注意:A 發送的ACK的值為 301, 原因是 B 的 SYN 中的 SEQ 是 300. A 發送的 SEQ 是 101,原因是上一次的請求中序列號已經增長到了 100. 下一個可用的序列號就是 101.
    在B接收到 A 的 ACK 之后,它的狀態切換為 ESTABLSHED. 至此,三次握手已經完成,一個 TCP 連接已經成功建立。
  • 在這條 TCP 連接上可以進行數據傳輸.
  • 在了解了基本的流程之后,我們來使用 wireshark 包應用以下所學:

    如下圖,忽略其中的黑色記錄,一共四條記錄,對應于上圖中的 2-5.

    接下來,我們詳細看看每條記錄

    客戶端 SYN

    這是建立 TCP 連接三次握手中的第一次

    這張圖涵蓋的信息很多,全部字段的含義在前文中已經描述過,這里我們僅僅關注個別字段.

  • Flags 字段中 SYN 標記為 1. 表明當前 TCP 包是一個 SYN 包. 首先發送這個數據包的 TCP 段為請求建立 TCP 連接的端點.
  • Sequence Number 字段的值為 2292773402. Wireshark 為了方便我們查看,引入另外一個字段 relative sequence number. 這個字段的值是基于 initial sequence number 計算所得. 正如前文 TCP 基礎中所說,當當前 TCP 包是一個 SYN 包時,Sequence number 就是 Initial Sequence Number, 因此 這里 relative sequence number 的值是 0.
  • 服務端 SYN + ACK

    這是建立 TCP 連接三次握手中的第二次。

  • Flags 字段中 SYN 和 ACK 字段均為 1
  • Sequence Number 字段的值為 4127119125 (前面說過,客戶端的 SEQ 和 服務端的 SEQ 是獨立的,他們之間沒有聯系), Relative Sequence Number 為 0.
  • Acknowledge Number 字段的值為 2292773403. 客戶段發送的 SYN 中 的 SEQ 值是 2292773402. 序列號 2292773403 告訴客戶端 2292773403以及之前的所有數據已經收到。 在接收到這個響應之后, 客戶端便可以確信服務段收到了自己發送的 SYN 包.
  • 客戶端 ACK

    這是建立 TCP 連接三次握手中的第三次

  • Flags 字段 ACK 為 1
  • Sequence Number 的值為 2292773403. 這個值于服務端發送給我們 SYN+ACK 包中的 ACK 值相同.
  • Acknowledge Number 的值為 4127119126. 這里需要注意服務第發送的 SYN+ACK 包中的 SEQ 的值為 4127119125.
  • 至此,這個 TCP 連接成功建立。

    特殊情況: 雙方同時請求建立連接

    在一個 TCP 建立成功之前,連接雙方是沒有任何關于對方的信息的。因此,存在一種巧合,那就是雙方同時發起建立TCP連接的請求. 這里我們來看一下這個特殊情況.

    圖中 "… " 用來表示該數據包正在網絡上傳輸,對方還未收到.

    注意,這里圖中雖然對數據包進行 1-7 的編號,但是對于雙方任何一方,都是獨立的. 也就是說,接收數據的先后是不確定的,有可能 B 先接收到 A 的包,也有可能 A 先接受到 B 的包。 這里我們并沒有明確的指定哪一方為 服務端,哪一方為客戶端,因此這里的結論都是成立的.

  • 初始狀態下,雙方均處于 CLOSED 狀態. 存在這種可能: 某一時刻雙發同時發送自己的 SYN 給對方,請求建立一條 TCP 連接.
  • 在某一時間點,A 發送 SYN 到 B 請求建立 TCP 連接. 此時,A 的狀態切換為 SYN-SENT
  • B 在未收到 A 發送的 SYN 包時,發送了自己的 SYN 給 A,請求建立一條連接. 此時,B 的狀態也切換為 SYN-SENT. 在接收到 B 發送的 SYN 之后,A 的狀態切換為 SYN-RECEIVED.
  • 此時,A 發送的 SYN 到達 B 端。B 收到了 A 發送的 SYN 包,狀態切換為 SYN-RECEIVED.
  • 在第三步之后,A的狀態一旦變成SYN-RECEIVED, 他就需要發送對應的 SYN+ACK 給 B,以確認自己接收到了 B 發送的 SYN. 并將自己的狀態切換為 ESTABLISHED. 這里注意,它發送完 SYN+ACK 之后,只是單方的進入 ESTABLISHED 狀態,對應狀態依然為 SYN-RECEIVED.
  • 在第四步之后, B的狀態一旦變成SYN-RECEIVED,它也要發送 SYN+ACK. 并切換狀態為 ESTABLISHED。
  • B 收到 A 發送的 SYN+ACK。 至此,雙方均進入 ESTABLISHED 狀態,一個連接已然建立成功.
  • 特殊情況: 舊的重復的 SYN

    TCP 協議的設計為三次握手的一個很重要原因就是處理舊的重復的SYN包

    RFC793 原文: The principle reason for the three-way handshake is to prevent old
    duplicate connection initiations from causing confusion

    這里我們就來看看它是如何處理的。

    看下圖的 TCP 包流程:

  • 初始狀態下, A 為客戶端,處于 CLOSED 狀態。 B 為服務端,處于LISTEN狀態
  • 某一時刻,A 發送 SYN 給 B,請求建立 TCP 連接
  • B 在收到 A 剛剛發送的 SYN 包之前, 收到了一個舊的重復的來自 A 的 SYN.
  • 對于 B 段來說,在收到來自 A 的 SYN 包時,它是不知道那是一個舊的重復的 SYN 包的,因此它就想就受到一個普通的 SYN一樣響應這個 SYN 包. 發送 SYN+ACK 進行確認.
  • A 端收到來自 B 段的 SYN+ACK, 發現其中的 ACK 字段的值不正確. 因為自己發送的 SYN 中 SEQ 值為 100,響應SYN+ACK包中的 ACK的值應該為 101,但是它收到的 SYN+ACK包中的ACK的值卻是91. 在收到這個非法的SYN+ACK之后,A 段發送 RST,并附上錯誤的SEQ序列號. B 端收到A發送過來的 RST 之后,便得知 A 重置了上一個SYN想要建立的TCP連接,B 段重置所有關于為上一個 SYN 所記錄的狀態,并重新回到 LISTEN 狀態.
  • 對于 TCP 協議來說,數據是不會丟失的,也就是說 B 段遲早會收到 A 發送的 SYN(SEQ=100). B 端收到 A 的 RST 之后,狀態切換到了 LISTEN之后, A 發送 SYN(SEQ=100)到達,此時B依然回像通常情況一樣. 如果 SYN(SEQ=100)到達 B 段早于 A 發送的 RST,將會是一個更復雜的情況,涉及到雙發均發送 RST 的場景. 這里能力有限,略掉.
  • B 在收到正確的 SYN+ACK之后,發送自己的 SYN 給 A
  • A 在發送自己的 SYN+ACK給B,這樣之后,一個 TCP 連接成功建立.
  • 如果剔除上述流程中 3-5,我們會發現這就是一個普通的 TCP 連接的三次握手流程. 厲害的地方在于,引入三次握手建立連接的機制,TCP 可以優雅的處理掉由于網絡不可靠所導致的非法SYN的數據包。 厲害👍

    Half-Open connections

    這里我們將 “Half-Open connection” 稱作 “半連接狀態的鏈接”.

    什么是半連接狀態的鏈接?
    B方鏈接已經關閉或者由于其他原因而奔潰掉,但是A方不知道B方的情況,此時 A 方持有的就是一個半連接狀態的鏈接.

    我們通過一個例子來描述半連接狀態的鏈接

  • 在某一時刻,A段的鏈接崩潰掉。假設奔潰的原因是A端物理內存不足. B 端未收到任何通知
  • 在A端從錯誤中回復過來之后,(假設)用戶嘗試發送數據從原先的 TCP 連接上,A 端TCP模塊會返回類似的 “connection not open”錯誤,此時 A 端TCP狀態為 CLOSED, B 端不知道 A 端的情況,因此狀態依然為 ESTABLISHED.
  • A 端發現 TCP 錯誤后,嘗試重新建立原先的 TCP 鏈接,發送SYN到 B 端
  • B 端收到 A 的 SYN 之后,發現收到的 SEQ(400) 于自己期待的 SEQ(100) 無法匹配, 因此不對這個 SYN 進行確認,而是發送自已認為正確的 SEQ(100) 給 A 端.
  • A 端收到 B 端發送的 SYN+ACK 之后,發現收到的 SEQ(100) 與自己剛剛發送的 SYN 中的 SEQ(400)不一致,因此得知自己的TCP狀態已經與B端不一致了。因此,發送 RST 重置當前的 TCP 鏈接.
  • 在上述步驟之后,上一個 TCP 鏈接依然被重置,雙方不再維護上一個TCP鏈接的任何狀態.
  • 這里 A 端重新發送 SYN 請求建立一個全新的 TCP 鏈接. 至此,已經走上了正路,在正常的三次握手之后,一個新的 TCP 鏈接即將建立.
  • 另外一種情況#####

    這里還有一個更有趣的情況. 考慮下圖的形況

  • A 端已然崩潰掉. B 端對此一無所知.
  • 此時, B 端認為鏈接一切正常,在該TCP鏈接上往 A 發送數據.
  • A 端收到這個數據之后,發現這個 TCP 鏈接并不存在,因此直接發送 RST 通知對方重置鏈接.
  • Reset

    何時 TCP 會發送 RST?
    通常來說,當 TCP 接收到一個明顯不是給當前連接的數據時,必須發送 RST。 當不是很明顯時,不應該發送 RST.

    發送 RST的原則:#####
  • 當當前 TCP 連接不存在時,對方發送任何數據到此(除過RST),我們會發送 RST.

    在這種情況下,如果從對方收到的數據包是包含ACK,那么 RST 中的 SEQ 會被置為 ACK 中包含的 SEQ,其他情況下 RST 中的 SEQ 會被置為0且 ACK 字段被置為 SEQ + 接收到的數據的長度. 連接狀態維持為 CLOSED.

  • 當當前 TCP 連接處于正在建立的狀態(LISTEN,SYN-SENT 或 SYN-RECIEVED, RFC中成為 非同步狀態), 接收到的數據卻包含了非法的 ACK 值,我們會發送 RST.

  • 當當前 TCP 處于同步的狀態(ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT), 此時收到一個非法的TCP數據包(錯誤的 SEQ或者錯誤的 ACK值), 我們應該發送一個ACK,其中包含當前的發送SEQ和一個 ACK值表明我們期待收到的下一個TCP數據包的序列號. 此時,維持當前 TCP 的狀態不變.

    這種情況的一個例子就是我們在半連接狀態的連接小節中第一張圖的 步驟 4.

  • END!

    總結

    以上是生活随笔為你收集整理的协议簇:TCP 解析: 建立连接的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。