diff --git a/src/essay/web/tcp.md b/src/essay/web/tcp.md index 71b680ca..3a1a4685 100644 --- a/src/essay/web/tcp.md +++ b/src/essay/web/tcp.md @@ -11,53 +11,69 @@ Network 中的 IP 是一種不考慮連線的協定,他只需要負責把封 換句話說,TCP 是被設計成雙向(bidirectional)、序列性(ordered)和可靠(reliable)的資料傳輸協定。 -- 可靠:透過反覆寄送確認信號(Acknowledge,或簡稱 ACK) -- 序列:透過 Sequence(或簡稱 SEQ) 和 Acknowledgement()的編號確認順序 -- 雙向:開啟連線時,這個連線雙方都可以寫入和讀取的 +- 雙向:開啟連線時,這個連線雙方都可以寫入和讀取的; +- 序列:透過序列(Sequence 或簡稱 SEQ) 和確認(Acknowledgement 或簡稱 ACK)的編號確認; +- 可靠:透過反覆寄送、檢查信號 ACK,確認雙方認知一致。 ## 內容物 -![TCP 標頭格式](https://i.imgur.com/3nh6DOI.png) +![TCP 標頭的可能內容物](https://i.imgur.com/3nh6DOI.png) > [鄭中勝](https://notfalse.net/26/tcp-seq) -TCP 會透過上述各種編號和訊號來完成連線所需的溝通。當建立連線(三次握手)後,雙方就不存在監聽方和發起方。兩者皆可以做監聽和送訊息,同時雙方也都可以要求中斷連線,並且雙方都要同意關閉才能真正完整關閉連線(四次揮手)。其完整生命的程如下: +TCP 會透過上述各種編號和標記來完成連線所需的溝通。 +當建立連線(三次握手)後,雙方就不存在監聽方和發起方。 +兩者皆可以做監聽和送訊息,同時雙方也都可以要求中斷連線, +並且雙方都要同意關閉連線,此時連線才能優雅而完整的關閉連線(四次揮手)。 +其完整生命的程如下: ![TCP 狀態流程](https://imgur.com/jeS7mge.png) -各個信號(Flags)代表意義下段展示。 +建立連線: + +- 監聽方透過 [socket API](#bsd-socket-api) CONNECT 來等待連線; +- 請求方 *要求建立*; +- 監聽方 *同樣要求建立* 且 *同意該請求*; +- 請求方 *同意建立請求* 自此,連線完成建立。 + 此時,請求方可能會同時把資料一起送出。 + +關閉連線: + +- 任意一方 *要求關閉*,進入主動關閉方; +- 收到的人,照常回應 ACK 同步認知,進入關閉等待期。 + 如確認資料都送出,且同意關閉後會同樣送出 *關閉要求* 並結束該連線; +- 此時,主動關閉方根據根據收到的標記,進入不同狀態,最終走入暫置區(`TIME_WAIT`)。 + +各個標記(flag)代表的意義在下段展示。 ### TCP 信號 不同的 TCP 信號代表這個 TCP 段(segment)的意義是什麼, 以下依照該信號在封包的位置順序來排列: -- Reserved -- Accurate echo -- Congestion Window Reduced -- Echo, ECH -- Urgent, URG - - 緊急的封包,告知接收方這個封包不需要進入佇列(queue),請直接處理 - - 會出現的場景還沒看過 -- Acknowledgment, ACK +- Reserved:保留,供未來可能需求使用; +- Explicit Congestion Notification, ECN:一種明確告知接收方壅塞的協定,避免丟包; +- Urgent, URG,緊急的封包: + - 告知接收方這個封包不需要進入佇列(queue),請直接處理; + - 目前我沒看過這個使用的實際場景。 +- Acknowledgment, ACK,代表我收到你剛剛的封包了: - 通常用來告知對方,我收到你剛剛傳的信號了; - 有時會夾帶其他信號,表明同意某些要求, - 例如 SYN+ACK 代表我收到你的連線要求,並且同意你的連線 -- Push, PSH + 例如 SYN+ACK 代表我收到你的連線要求,我也同時告知對方這個連線應該要被建立。 +- Push, PSH,代表有資料需要儲存: - 添加這個信號代表接收方不需要做暫存,可以直接把資料往上傳遞 - 通常用在小段的資料,因為大資料會被分成多段,然後會有順序議題 -- Reset, RST,已經捨棄的連線又收到訊號(例如 ACK),就會回傳 +- Reset, RST,代表我不認識這個封包: + - 已經捨棄的連線又收到訊號(例如 ACK),就會回應此; - 埠不存在,通常是因為你請求的埠沒被打開; - IP 不存在,通常是因為你監聽的 IP 不是 `0.0.0.0:port`; - - 連線被棄用,對方(接收者)會出現 Connection closed by peer 的錯誤; + - 連線被棄用,對方會出現 Connection closed by peer 的錯誤; - 對方的佇列(queue)已經滿了; - 防火牆清除了 session table,導致不認識這段連線,就可能回傳該訊號。 -- Synchronize, SYN - - 開啟連線 - - 被動方會和 ACK 一起搭配 -- Finish, FIN - - 結束連線 - - 被動方會和 ACK 一起搭配 +- Synchronize, SYN,代表我們來建立連線吧: + - 接受者需要回應 ACK。 +- Finish, FIN,代表連線的關閉: + - 被動方需要回應 ACK。 ### 三次握手