# :-: TCP三次握手
 
 


(1)首先客戶端向服務器端發送一段TCP報文,其中:標記位為SYN,表示“請求建立新連接”;序號為Seq=X(X一般為1);隨后客戶端進入**SYN-SENT階段**。
(2)服務器端接收到來自客戶端的TCP報文之后,結束LISTEN階段。并返回一段TCP報文,其中:標志位為SYN和ACK,表示“確認客戶端的報文Seq序號有效,服務器能正常接收客戶端發送的數據,并同意創建新連接”(即告訴客戶端,服務器收到了你的數據);序號為Seq=y;確認號為Ack=x+1,表示收到客戶端的序號Seq并將其值加1作為自己確認號Ack的值;隨后服務器端進入**SYN-RCVD階段**。
(3)客戶端接收到來自服務器端的確認收到數據的TCP報文之后,明確了從客戶端到服務器的數據傳輸是正常的,**結束SYN-SENT階段**。并返回最后一段TCP報文。其中:標志位為ACK,表示“確認收到服務器端同意連接的信號”(即告訴服務器,我知道你收到我發的數據了);序號為Seq=x+1,表示收到服務器端的確認號Ack,并將其值作為自己的序號值;確認號為Ack=y+1,表示收到服務器端序號Seq,并將其值加1作為自己的確認號Ack的值;隨后客戶端進入**ESTABLISHED階段**。服務器收到來自客戶端的“確認收到服務器數據”的TCP報文之后,明確了從服務器到客戶端的數據傳輸是正常的。結束SYN-SENT階段,進入**ESTABLISHED階段**。
在客戶端與服務器端傳輸的TCP報文中,雙方的確認號Ack和序號Seq的值,都是在彼此Ack和Seq值的基礎上進行計算的,這樣做保證了TCP報文傳輸的連貫性。一旦出現某一方發出的TCP報文丟失,便無法繼續"握手",以此確保了"三次握手"的順利完成。
此后客戶端和服務器端進行正常的數據傳輸。這就是“三次握手”的過程。

*****
*****
*****
 
 
# :-: TCP四次揮手
 
 


 
(1)首先客戶端想要釋放連接,向服務器端發送一段TCP報文,其中:標記位為FIN,表示“請求釋放連接“;序號為Seq=U;隨后客戶端進入FIN-WAIT-1階段,即半關閉階段。并且停止在客戶端到服務器端方向上發送數據,但是客戶端仍然能接收從服務器端傳輸過來的數據。注意:這里不發送的是正常連接時傳輸的數據(非確認報文),而不是一切數據,所以客戶端仍然能發送ACK確認報文。
(2)服務器端接收到從客戶端發出的TCP報文之后,確認了客戶端想要釋放連接,隨后服務器端結束ESTABLISHED階段,進入CLOSE-WAIT階段(半關閉狀態)并返回一段TCP報文,其中:標記位為ACK,表示“接收到客戶端發送的釋放連接的請求”;序號為Seq=V;確認號為Ack=U+1,表示是在收到客戶端報文的基礎上,將其序號Seq值加1作為本段報文確認號Ack的值;隨后服務器端開始準備釋放服務器端到客戶端方向上的連接。客戶端收到從服務器端發出的TCP報文之后,確認了服務器收到了客戶端發出的釋放連接請求,隨后客戶端結束FIN-WAIT-1階段,進入FIN-WAIT-2階段前"兩次揮手"既讓服務器端知道了客戶端想要釋放連接,也讓客戶端知道了服務器端了解了自己想要釋放連接的請求。于是,可以確認關閉客戶端到服務器端方向上的連接了。
(3)服務器端自從發出ACK確認報文之后,經過CLOSED-WAIT階段,做好了釋放服務器端到客戶端方向上的連接準備,再次向客戶端發出一段TCP報文,其中:標記位為FIN,ACK,表示“已經準備好釋放連接了”。注意:這里的ACK并不是確認收到服務器端報文的確認報文。序號為Seq=W;確認號為Ack=U+1;表示是在收到客戶端報文的基礎上,將其序號Seq值加1作為本段報文確認號Ack的值。隨后服務器端結束CLOSE-WAIT階段,進入LAST-ACK階段。并且停止在服務器端到客戶端的方向上發送數據,但是服務器端仍然能夠接收從客戶端傳輸過來的數據。
(4)客戶端收到從服務器端發出的TCP報文,確認了服務器端已做好釋放連接的準備,結束FIN-WAIT-2階段,進入TIME-WAIT階段,并向服務器端發送一段報文,其中:標記位為ACK,表示“接收到服務器準備好釋放連接的信號”。序號為Seq=U+1;表示是在收到了服務器端報文的基礎上,將其確認號Ack值作為本段報文序號的值。確認號為Ack=W+1;表示是在收到了服務器端報文的基礎上,將其序號Seq值作為本段報文確認號的值。隨后客戶端開始在TIME-WAIT階段等待2MSL。服務器端收到從客戶端發出的TCP報文之后結束LAST-ACK階段,進入CLOSED階段。由此正式確認關閉服務器端到客戶端方向上的連接。客戶端等待完2MSL之后,結束TIME-WAIT階段,進入CLOSED階段,由此完成“四次揮手”。
*****
 
## 為什么連接的時候是**三次握手**,關閉的時候卻是**四次揮手**?
**答**:
TCP建立連接時之所以只需要"三次握手",是因為在第二次"握手"過程中,服務器端發送給客戶端的TCP報文是以SYN與ACK作為標志位的。SYN是請求連接標志,表示服務器端同意建立連接;ACK是確認報文,表示告訴客戶端,服務器端收到了它的請求報文。即SYN建立連接報文與ACK確認接收報文是在同一次"握手"當中傳輸的,所以"三次握手"不多也不少,正好讓雙方明確彼此信息互通。TCP釋放連接時之所以需要“四次揮手”,是因為FIN釋放連接報文與ACK確認接收報文是分別由第二次和第三次"握手"傳輸的。
為何建立連接時一起傳輸,釋放連接時卻要分開傳輸 **?**
**建立連接時**,被動方服務器端結束CLOSED階段進入“握手”階段并不需要任何準備,可以直接返回SYN和ACK報文,開始建立連接。**釋放連接時**,被動方服務器,突然收到主動方客戶端釋放連接的請求時并不能立即釋放連接,因為還有必要的**數據需要處理**,所以服務器先返回ACK確認收到報文,經過CLOSE-WAIT階段準備好釋放連接之后,才能返回FIN釋放連接報文。
所以是“三次握手”,“四次揮手”。
*****
 
## 為什么客戶端在**TIME-WAIT階**段要等**2MSL**?
答:為的是確認服務器端是否收到客戶端發出的ACK確認報文當客戶端發出最后的ACK確認報文時,并不能確定服務器端能夠收到該段報文。所以客戶端在發送完ACK確認報文之后,會設置一個時長為**2MSL的計時器**。MSL指的是Maximum Segment Lifetime:一段TCP報文在傳輸過程中的最大生命周期。2MSL即是服務器端發出為FIN報文和客戶端發出的ACK確認報文所能保持有效的最大時長。
服務器端在1MSL內沒有收到客戶端發出的ACK確認報文,就會再次向客戶端發出FIN報文;如果客戶端在2MSL內,再次收到了來自服務器端的FIN報文,說明服務器端由于各種原因沒有接收到客戶端發出的ACK確認報文。客戶端再次向服務器端發出ACK確認報文,計時器重置,重新開始2MSL的計時;否則客戶端在2MSL內沒有再次收到來自服務器端的FIN報文,說明服務器端正常接收了ACK確認報文,客戶端可以進入**CLOSED階段**,完成“四次揮手”。所以,客戶端要經歷時長為2SML的TIME-WAIT階段;這也是為什么客戶端比服務器端晚進入CLOSED階段的原因。
*****
 
## 為什么不能用**兩次**握手進行連接?
答:3次握手完成兩個重要的功能,既要雙方做好發送數據的準備工作(雙方都知道彼此已準備好),也要允許雙方就初始序列號進行協商,這個序列號在握手過程中被發送和確認。
現在把三次握手改成僅需要兩次握手,**死鎖**是可能發生的。作為例子,考慮計算機S和C之間的通信,假定C給S發送一個連接請求分組,S收到了這個分組,并發 送了確認應答分組。按照兩次握手的協定,S認為連接已經成功地建立了,可以開始發送數據分組。可是,C在S的應答分組后(S=>C)傳輸數據過程中造成數據丟失,將不知道S 是否已準備好,也不知道S建立什么樣的序列號,C甚至懷疑S是否收到自己的連接請求分組。在這種情況下,C認為連接還未建立成功,將忽略S發來的任何數據分 組,只等待連接確認應答分組。而S在發出的分組超時后,重復發送同樣的分組。這樣就形成了死鎖。
**自己理解:**
采用三次握手是為了防止失效的連接請求報文段突然又傳送到主機B,因而產生錯誤。失效的連接請求報文段是指:主機A發出的連接請求沒有收到主機B的確認,于是經過一段時間后,主機A又重新向主機B發送連接請求,且建立成功,順序完成數據傳輸。考慮這樣一種特殊情況,主機A第一次發送的連接請求并沒有丟失,而是因為網絡節點導致延遲達到主機B,主機B以為是主機A又發起的新連接,于是主機B同意連接,并向主機A發回確認,但是此時主機A根本不會理會,主機B就一直在等待主機A發送數據,導致主機B的資源浪費。**如果三次,就比較保險,能避免這種失效鏈接重連的情況**。三次通信是理論上的**最小值**. 所以三次握手不是TCP本身的要求, 而是為了滿足"在不可靠信道上可靠地傳輸信息"這一需求所導致的,自然也可以四次五次。`如果是兩次握手:此時連接就建立了,B會一直等待A發送數據,從而白白浪費B的資源`。`如果是三次握手:由于A沒有發起連接請求,也就不會理會B的連接響應,B沒有收到A的確認連接,就會關閉掉本次連接`
- 空白目錄
- containerd
- php
- php常用函數
- 點語法
- 依賴注入
- 反射
- 迭代器和yield
- array_walk
- str_replace
- openssl_decrypt
- array_merge
- 閉包
- 深拷貝與淺拷貝
- 面向對象
- 魔術方法
- __invoke
- __isset 和 __unset
- __clone
- 常用知識點
- 訪問權限
- 抽象類
- 多態
- php框架
- tp
- tp3
- tp5
- job
- laravel
- 中間件
- laravel閉包
- symfony
- 小工具
- phpexcel
- xlswrite
- 設計模式
- 事件event
- 里氏替換原則
- 借鑒
- RESTful API
- 環境安裝
- 編譯安裝
- 編譯安裝后擴展補充
- php小記錄
- php-fpm
- 容器(Container)
- composer
- composer踩坑
- mysql
- 基礎知識
- 外鍵
- 索引
- 觸發器
- 定時器
- 分表
- 分區
- 連接查詢
- 事務
- 鎖機制
- 視圖
- 存儲過程
- 查詢
- 字符截取
- 批量修改表名(前綴)
- explain
- when_case
- pdo
- mysql優化
- 主從復制
- 權限分配
- 實用例子
- 查詢用戶
- 常見問題
- 5.7group by問題
- 遠程鏈接慢問題
- 查看進程
- 遠程訪問
- 常用小記
- mysqldump
- 備份還原
- 系統盤遷移數據盤
- 安裝sql
- 安裝MariaDB
- docker
- 安裝docker
- 配置centos開發環境
- docker運行程序
- rabbitmq
- 刪除無用鏡像
- 解決Centos firewalld導致的docker容器內無法訪問外網,無法訪問其他容器(host沒辦法解析)
- docker-compose
- docker-selenium
- ports 配置
- docker-compose-settings
- 安裝
- docker-compose常用配置
- docker常用命令
- build
- docker-hub加速
- docker-run
- Dockerfile
- apt-get update 無法升級
- 阿里打標簽
- 打包流程
- docker-network
- ufw 允許 docker 容器聯網
- 安裝containerd
- linux
- centos7
- 常用語法
- chmod
- chown
- find
- grep
- /etc/passwd
- chattr
- In軟連接
- 文件目錄大小
- xargs
- 管道用法
- top
- free
- 端口占用
- 壓縮解壓
- tar
- gzip
- zip
- 2>&1
- 環境變量
- 服務管理
- systemctl
- sed
- shell腳本
- time
- journal
- history
- linux-set
- linux-curl
- cp
- umask
- mkdir
- http狀態碼
- awk
- lsof
- crontab
- supervisor
- 常用命令匯總
- 用戶權限
- 普通用戶添加sudo權限
- sudo su
- 添加用戶
- 查看用戶信息
- 修改用戶信息
- 特殊權限
- 系統命令
- 常用小技巧
- vim小技巧
- 防火墻
- 常用規則
- iptables
- 磁盤清理
- 分區掛載
- linux-sh
- tmux
- 多命令執行
- 常用工具
- telnet
- ip轉發
- nohup
- watch
- dig
- 查看磁盤IO
- ssh
- 修改ssh端口
- ssh免密登錄
- 配置文件
- 公鑰分發
- xsync
- 國內鏡像站
- github加速
- 測網速
- 網卡
- 清理日志備份
- 配置sftp
- shell
- rpm
- 安全
- 安裝openssl
- 安裝openssh
- 禁用selinux和防火墻
- lanp環境安裝
- versionTool
- git
- git基本用法
- Gogs搭建
- git鉤子
- git的習慣配置
- phpStorm設置git bash
- git bash 設置代理
- gitignore 不起作用的解決辦法
- gitea搭建
- 同步主干到fork
- git修改地址
- svn
- svn基本操作
- svn 鉤子應用
- svn多版本操作
- Go語言
- Go語言基礎
- 安裝環境
- linux安裝
- window安裝
- 工具使用教程
- linux終端分屏Screen
- keepass 帳號密碼管理
- phpstorm
- 去掉window換行符
- php_cs
- 自定義快捷模塊
- phpstorm快捷鍵
- curl
- 正則
- 設計架構
- 設計模式的六大原則
- 計算機基礎
- TCP三次握手
- OSI7層
- http狀態返回碼
- 前端框架
- Vue
- Angular
- React
- node
- 服務端渲染(SSR)
- MVVM
- nuxt
- pm2
- js
- Promise
- es6
- 常用站點
- 工具類
- 學習類
- ps常用命令
- nginx
- 緩存
- 配置
- TCP
- 常用配置
- ng優先級
- vhost注意點
- nginx第一層驗證
- 轉發(跨域問題)
- 404
- nginx日志格式化
- 重啟腳本
- 寶塔禁用境外ip訪問
- ng統計
- ng編譯安裝
- 防盜鏈
- 技術相關了解
- ddos
- xss
- mysql防注入
- csrf攻擊
- 郵箱系統原理
- DNS
- python
- Selenium
- 微信
- 公眾號
- 公眾號配置
- 用戶授權
- 小程序
- 公有云
- 華為云
- JAVA
- springboot
- windows
- service
- WSL
- 目錄遷移
- wsl2 踩坑
- NoSql
- mongodb
- 安裝mongodb
- redis
- redis-windows
- redis-linux
- openstack
- ====副業====
- 擼茅臺
- 網絡
- 單位換算
- DB
- clickhouse
- mac