[TOC]
## HTTP 1.0 和 HTTP 1.1 之間有哪些區別?
**HTTP 1.0和 HTTP 1.1** **有以下區別**:
* **連接方面**,http1.0 默認使用非持久連接,而 http1.1 默認使用持久連接。http1.1 通過使用持久連接來使多個 http 請求復用同一個 TCP 連接,以此來避免使用非持久連接時每次需要建立連接的時延。
* **資源請求方面**,在 http1.0 中,存在一些浪費帶寬的現象,例如客戶端只是需要某個對象的一部分,而服務器卻將整個對象送過來了,并且不支持斷點續傳功能,http1.1 則在請求頭引入了 range 頭域,它允許只請求資源的某個部分,即返回碼是 206(Partial Content),這樣就方便了開發者自由的選擇以便于充分利用帶寬和連接。
* **緩存方面**,在 http1.0 中主要使用 header 里的 If-Modified-Since、Expires 來做為緩存判斷的標準,http1.1 則引入了更多的緩存控制策略,例如 Etag、If-Unmodified-Since、If-Match、If-None-Match 等更多可供選擇的緩存頭來控制緩存策略。
* http1.1 中**新增了 host 字段**,用來指定服務器的域名。http1.0 中認為每臺服務器都綁定一個唯一的 IP 地址,因此,請求消息中的 URL 并沒有傳遞主機名(hostname)。但隨著虛擬主機技術的發展,在一臺物理服務器上可以存在多個虛擬主機,并且它們共享一個IP地址。因此有了 host 字段,這樣就可以將請求發往到同一臺服務器上的不同網站。
* http1.1 相對于 http1.0 還新增了很多**請求方法**,如 PUT、HEAD、OPTIONS 等。
## HTTP 1.1 和 HTTP 2.0 的區別,說說http3.x
* **二進制協議**:HTTP/2 是一個二進制協議。在 HTTP/1.1 版中,報文的頭信息必須是文本(ASCII 編碼),數據體可以是文本,也可以是二進制。HTTP/2 則是一個徹底的二進制協議,頭信息和數據體都是二進制,并且統稱為"幀",可以分為頭信息幀和數據幀。 幀的概念是它實現多路復用的基礎。
* **多路復用:**HTTP/2 實現了多路復用,HTTP/2 仍然復用 TCP 連接,但是在一個連接里,客戶端和服務器都可以同時發送多個請求或回應,而且不用按照順序一一發送,這樣就避免了"隊頭堵塞"【1】的問題。
* **數據流:**HTTP/2 使用了數據流的概念,因為 HTTP/2 的數據包是不按順序發送的,同一個連接里面連續的數據包,可能屬于不同的請求。因此,必須要對數據包做標記,指出它屬于哪個請求。HTTP/2 將每個請求或回應的所有數據包,稱為一個數據流。每個數據流都有一個獨一無二的編號。數據包發送時,都必須標記數據流 ID ,用來區分它屬于哪個數據流。
* **頭信息壓縮:**HTTP/2 實現了頭信息壓縮,由于 HTTP 1.1 協議不帶狀態,每次請求都必須附上所有信息。所以,請求的很多字段都是重復的,比如 Cookie 和 User Agent ,一模一樣的內容,每次請求都必須附帶,這會浪費很多帶寬,也影響速度。HTTP/2 對這一點做了優化,引入了頭信息壓縮機制。一方面,頭信息使用 gzip 或 compress 壓縮后再發送;另一方面,客戶端和服務器同時維護一張頭信息表,所有字段都會存入這個表,生成一個索引號,以后就不發送同樣字段了,只發送索引號,這樣就能提高速度了。
* **服務器推送:**HTTP/2 允許服務器未經請求,主動向客戶端發送資源,這叫做服務器推送。使用服務器推送提前給客戶端推送必要的資源,這樣就可以相對減少一些延遲時間。這里需要注意的是 http2 下服務器主動推送的是靜態資源,和 WebSocket 以及使用 SSE 等方式向客戶端發送即時數據的推送是不同的。
隊頭阻塞是由 HTTP 基本的“請求 - 應答”模型所導致的。HTTP 規定報文必須是“一發一收”,這就形成了一個先進先出的“串行”隊列。隊列里的請求是沒有優先級的,只有入隊的先后順序,排在最前面的請求會被最優先處理。如果隊首的請求因為處理的太慢耽誤了時間,那么隊列里后面的所有請求也不得不跟著一起等待,結果就是其他的請求承擔了不應有的時間成本,造成了隊頭堵塞的現象。
**說一下HTTP 3.0**

1. 流量控制、傳輸可靠性功能:QUIC在UDP的基礎上增加了一層來保證數據傳輸可靠性,它提供了數據包重傳、擁塞控制、以及其他一些TCP中的特性。
2. 集成TLS加密功能:目前QUIC使用TLS1.3,減少了握手所花費的RTT數。
3. 多路復用:同一物理連接上可以有多個獨立的邏輯數據流,實現了數據流的單獨傳輸,解決了TCP的隊頭阻塞問題。

* HTTP/3基于UDP協議實現了類似于TCP的多路復用數據流、傳輸可靠性等功能,這套功能被稱為QUIC協議。
## HTTP和HTTPS協議的區別
HTTP和HTTPS協議的主要區別如下:
* HTTPS協議需要CA證書,費用較高;而HTTP協議不需要;
* HTTP協議是超文本傳輸協議,信息是明文傳輸的,HTTPS則是具有安全性的SSL加密傳輸協議;
* 使用不同的連接方式,端口也不同,HTTP協議端口是80,HTTPS協議端口是443;
* HTTP協議連接很簡單,是無狀態的;HTTPS協議是有SSL和HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比HTTP更加安全。
## 當在瀏覽器中輸入 Google.com 并且按下回車之后發生了什么?
1. **解析URL:** 首先會對 URL 進行解析,分析所需要使用的傳輸協議和請求的資源的路徑。如果輸入的 URL 中的協議或者主機名不合法,將會把地址欄中輸入的內容傳遞給搜索引擎。如果沒有問題,瀏覽器會檢查 URL 中是否出現了非法字符,如果存在非法字符,則對非法字符進行轉義后再進行下一過程。
2. **緩存判斷:** 瀏覽器會判斷所請求的資源是否在緩存里,如果請求的資源在緩存里并且沒有失效,那么就直接使用,否則向服務器發起新的請求。
3. **DNS解析:** 下一步首先需要獲取的是輸入的 URL 中的域名的 IP 地址,首先會判斷本地是否有該域名的 IP 地址的緩存,如果有則使用,如果沒有則向本地 DNS 服務器發起請求。本地 DNS 服務器也會先檢查是否存在緩存,如果沒有就會先向根域名服務器發起請求,獲得負責的頂級域名服務器的地址后,再向頂級域名服務器請求,然后獲得負責的權威域名服務器的地址后,再向權威域名服務器發起請求,最終獲得域名的 IP 地址后,本地 DNS 服務器再將這個 IP 地址返回給請求的用戶。用戶向本地 DNS 服務器發起請求屬于遞歸請求,本地 DNS 服務器向各級域名服務器發起請求屬于迭代請求。
4. **獲取MAC地址:** 當瀏覽器得到 IP 地址后,數據傳輸還需要知道目的主機 MAC 地址,因為應用層下發數據給傳輸層,TCP 協議會指定源端口號和目的端口號,然后下發給網絡層。網絡層會將本機地址作為源地址,獲取的 IP 地址作為目的地址。然后將下發給數據鏈路層,數據鏈路層的發送需要加入通信雙方的 MAC 地址,本機的 MAC 地址作為源 MAC 地址,目的 MAC 地址需要分情況處理。通過將 IP 地址與本機的子網掩碼相與,可以判斷是否與請求主機在同一個子網里,如果在同一個子網里,可以使用 APR 協議獲取到目的主機的 MAC 地址,如果不在一個子網里,那么請求應該轉發給網關,由它代為轉發,此時同樣可以通過 ARP 協議來獲取網關的 MAC 地址,此時目的主機的 MAC 地址應該為網關的地址。
5. **TCP三次握手:** 下面是 TCP 建立連接的三次握手的過程,首先客戶端向服務器發送一個 SYN 連接請求報文段和一個隨機序號,服務端接收到請求后向服務器端發送一個 SYN ACK報文段,確認連接請求,并且也向客戶端發送一個隨機序號。客戶端接收服務器的確認應答后,進入連接建立的狀態,同時向服務器也發送一個ACK 確認報文段,服務器端接收到確認后,也進入連接建立狀態,此時雙方的連接就建立起來了。
6. **HTTPS握手:** 如果使用的是 HTTPS 協議,在通信前還存在 TLS 的一個四次握手的過程。首先由客戶端向服務器端發送使用的協議的版本號、一個隨機數和可以使用的加密方法。服務器端收到后,確認加密的方法,也向客戶端發送一個隨機數和自己的數字證書。客戶端收到后,首先檢查數字證書是否有效,如果有效,則再生成一個隨機數,并使用證書中的公鑰對隨機數加密,然后發送給服務器端,并且還會提供一個前面所有內容的 hash 值供服務器端檢驗。服務器端接收后,使用自己的私鑰對數據解密,同時向客戶端發送一個前面所有內容的 hash 值供客戶端檢驗。這個時候雙方都有了三個隨機數,按照之前所約定的加密方法,使用這三個隨機數生成一把秘鑰,以后雙方通信前,就使用這個秘鑰對數據進行加密后再傳輸。
7. **返回數據:** 當頁面請求發送到服務器端后,服務器端會返回一個 html 文件作為響應,瀏覽器接收到響應后,開始對 html 文件進行解析,開始頁面的渲染過程。
8. **頁面渲染:** 瀏覽器首先會根據 html 文件構建 DOM 樹,根據解析到的 css 文件構建 CSSOM 樹,如果遇到 script 標簽,則判端是否含有 defer 或者 async 屬性,要不然 script 的加載和執行會造成頁面的渲染的阻塞。當 DOM 樹和 CSSOM 樹建立好后,根據它們來構建渲染樹。渲染樹構建好后,會根據渲染樹來進行布局。布局完成后,最后使用瀏覽器的 UI 接口對頁面進行繪制。這個時候整個頁面就顯示出來了。
9. **TCP四次揮手:** 最后一步是 TCP 斷開連接的四次揮手過程。若客戶端認為數據發送完成,則它需要向服務端發送連接釋放請求。服務端收到連接釋放請求后,會告訴應用層要釋放 TCP 鏈接。然后會發送 ACK 包,并進入 CLOSE\_WAIT 狀態,此時表明客戶端到服務端的連接已經釋放,不再接收客戶端發的數據了。但是因為 TCP 連接是雙向的,所以服務端仍舊可以發送數據給客戶端。服務端如果此時還有沒發完的數據會繼續發送,完畢后會向客戶端發送連接釋放請求,然后服務端便進入 LAST-ACK 狀態。客戶端收到釋放請求后,向服務端發送確認應答,此時客戶端進入 TIME-WAIT 狀態。該狀態會持續 2MSL(最大段生存期,指報文段在網絡中生存的時間,超時會被拋棄) 時間,若該時間段內沒有服務端的重發請求的話,就進入 CLOSED 狀態。當服務端收到確認應答后,也便進入 CLOSED 狀態。
## HTTPS協議
**什么是HTTPS協議?**
* 超文本傳輸安全協議(Hypertext Transfer Protocol Secure,簡稱:HTTPS)是一種通過計算機網絡進行安全通信的傳輸協議。HTTPS經由HTTP進行通信,利用SSL/TLS來加密數據包。HTTPS的主要目的是提供對網站服務器的身份認證,保護交換數據的隱私與完整性。

* HTTP協議采用**明文傳輸**信息,存在**信息竊聽**、**信息篡改**和**信息劫持**的風險,而協議TLS/SSL具有**身份驗證**、**信息加密**和**完整性校驗**的功能,可以避免此類問題發生。
* 安全層的主要職責就是**對發起的HTTP請求的數據進行加密操作** 和 **對接收到的HTTP的內容進行解密操作**。
**TLS/SSL的工作原理**
* **TLS/SSL**全稱**安全傳輸層協議**(Transport Layer Security), 是介于TCP和HTTP之間的一層安全協議,不影響原有的TCP協議和HTTP協議,所以使用HTTPS基本上不需要對HTTP頁面進行太多的改造。
* TLS/SSL的功能實現主要依賴三類基本算法:**散列函數hash**、**對稱加密**、**非對稱加密**。這三類算法的作用如下:
* 基于散列函數驗證信息的完整性
* 對稱加密算法采用協商的秘鑰對數據加密
* 非對稱加密實現身份認證和秘鑰協商

1. **散列函數hash**
* 常見的散列函數有MD5、SHA1、SHA256。該函數的特點是單向不可逆,對輸入數據非常敏感,輸出的長度固定,任何數據的修改都會改變散列函數的結果,可以用于防止信息篡改并驗證數據的完整性。
* **特點:** 在信息傳輸過程中,散列函數不能三都實現信息防篡改,由于傳輸是明文傳輸,中間人可以修改信息后重新計算信息的摘要,所以需要對傳輸的信息和信息摘要進行加密。
2. **對稱加密**
* 對稱加密的方法是,雙方使用同一個秘鑰對數據進行加密和解密。但是對稱加密的存在一個問題,就是如何保證秘鑰傳輸的安全性,因為秘鑰還是會通過網絡傳輸的,一旦秘鑰被其他人獲取到,那么整個加密過程就毫無作用了。 這就要用到非對稱加密的方法。
* 常見的對稱加密算法有AES-CBC、DES、3DES、AES-GCM等。相同的秘鑰可以用于信息的加密和解密。掌握秘鑰才能獲取信息,防止信息竊聽,其通訊方式是一對一。
* **特點:** 對稱加密的優勢就是信息傳輸使用一對一,需要共享相同的密碼,密碼的安全是保證信息安全的基礎,服務器和N個客戶端通信,需要維持N個密碼記錄且不能修改密碼。
3. **非對稱加密**
* 非對稱加密的方法是,我們擁有兩個秘鑰,一個是公鑰,一個是私鑰。公鑰是公開的,私鑰是保密的。用私鑰加密的數據,只有對應的公鑰才能解密,用公鑰加密的數據,只有對應的私鑰才能解密。我們可以將公鑰公布出去,任何想和我們通信的客戶, 都可以使用我們提供的公鑰對數據進行加密,這樣我們就可以使用私鑰進行解密,這樣就能保證數據的安全了。但是非對稱加密有一個缺點就是加密的過程很慢,因此如果每次通信都使用非對稱加密的方式的話,反而會造成等待時間過長的問題。
* 常見的非對稱加密算法有RSA、ECC、DH等。秘鑰成對出現,一般稱為公鑰(公開)和私鑰(保密)。公鑰加密的信息只有私鑰可以解開,私鑰加密的信息只能公鑰解開,因此掌握公鑰的不同客戶端之間不能相互解密信息,只能和服務器進行加密通信,服務器可以實現一對多的的通信,客戶端也可以用來驗證掌握私鑰的服務器的身份。
* **特點:** 非對稱加密的特點就是信息一對多,服務器只需要維持一個私鑰就可以和多個客戶端進行通信,但服務器發出的信息能夠被所有的客戶端解密,且該算法的計算復雜,加密的速度慢。
綜合上述算法特點,TLS/SSL的工作方式就是客戶端使用非對稱加密與服務器進行通信,實現身份的驗證并協商對稱加密使用的秘鑰。對稱加密算法采用協商秘鑰對信息以及信息摘要進行加密通信,不同節點之間采用的對稱秘鑰不同,從而保證信息只能通信雙方獲取。這樣就解決了兩個方法各自存在的問題。
**數字證書是什么?**
* 現在的方法也不一定是安全的,因為沒有辦法確定得到的公鑰就一定是安全的公鑰。可能存在一個中間人,截取了對方發給我們的公鑰,然后將他自己的公鑰發送給我們,當我們使用他的公鑰加密后發送的信息,就可以被他用自己的私鑰解密。然后他偽裝成我們以同樣的方法向對方發送信息,這樣我們的信息就被竊取了,然而自己還不知道。為了解決這樣的問題,可以使用數字證書。
* 首先使用一種 Hash 算法來對公鑰和其他信息進行加密,生成一個信息摘要,然后讓有公信力的認證中心(簡稱 CA )用它的私鑰對消息摘要加密,形成簽名。最后將原始的信息和簽名合在一起,稱為數字證書。當接收方收到數字證書的時候,先根據原始信息使用同樣的 Hash 算法生成一個摘要,然后使用公證處的公鑰來對數字證書中的摘要進行解密,最后將解密的摘要和生成的摘要進行對比,就能發現得到的信息是否被更改了。
* 這個方法最要的是認證中心的可靠性,一般瀏覽器里會內置一些頂層的認證中心的證書,相當于我們自動信任了他們,只有這樣才能保證數據的安全。
**HTTPS通信(握手)過程**
* HTTPS的通信過程如下:
1. 客戶端向服務器發起請求,請求中包含使用的協議版本號、生成的一個隨機數、以及客戶端支持的加密方法。
2. 服務器端接收到請求后,確認雙方使用的加密方法、并給出服務器的證書、以及一個服務器生成的隨機數。
3. 客戶端確認服務器證書有效后,生成一個新的隨機數,并使用數字證書中的公鑰,加密這個隨機數,然后發給服 務器。并且還會提供一個前面所有內容的 hash 的值,用來供服務器檢驗。
4. 服務器使用自己的私鑰,來解密客戶端發送過來的隨機數。并提供前面所有內容的 hash 值來供客戶端檢驗。
5. 客戶端和服務器端根據約定的加密方法使用前面的三個隨機數,生成對話秘鑰,以后的對話過程都使用這個秘鑰來加密信息。
**HTTPS的特點**
* HTTPS的**優點**如下:
1. 使用HTTPS協議可以認證用戶和服務器,確保數據發送到正確的客戶端和服務器;
2. 使用HTTPS協議可以進行加密傳輸、身份認證,通信更加安全,防止數據在傳輸過程中被竊取、修改,確保數據安全性;
3. HTTPS是現行架構下最安全的解決方案,雖然不是絕對的安全,但是大幅增加了中間人攻擊的成本;
* HTTPS的**缺點**如下:
1. HTTPS需要做服務器和客戶端雙方的加密個解密處理,耗費更多服務器資源,過程復雜;
2. HTTPS協議握手階段比較費時,增加頁面的加載時間;
3. SSL證書是收費的,功能越強大的證書費用越高;
4. HTTPS連接服務器端資源占用高很多,支持訪客稍多的網站需要投入更大的成本;
5. SSL證書需要綁定IP,不能再同一個IP上綁定多個域名。
**HTTPS是如何保證安全的?**
* 先理解兩個概念:
* 對稱加密:即通信的雙?都使?同?個秘鑰進?加解密,對稱加密雖然很簡單性能也好,但是?法解決?次把秘鑰發給對?的問題,很容易被?客攔截秘鑰。
* ?對稱加密:
1. 私鑰 + 公鑰= 密鑰對
2. 即?私鑰加密的數據,只有對應的公鑰才能解密,?公鑰加密的數據,只有對應的私鑰才能解密
3. 因為通信雙?的??都有?套??的密鑰對,通信之前雙?會先把??的公鑰都先發給對?
4. 然后對?再拿著這個公鑰來加密數據響應給對?,等到到了對?那?,對?再???的私鑰進?解密
* ?對稱加密雖然安全性更?,但是帶來的問題就是速度很慢,影響性能。
**解決?案:**
* 結合兩種加密?式,將對稱加密的密鑰使??對稱加密的公鑰進?加密,然后發送出去,接收?使?私鑰進?解密得到對稱加密的密鑰,然后雙?可以使?對稱加密來進?溝通。
* 此時?帶來?個問題,中間?問題:
* 如果此時在客戶端和服務器之間存在?個中間?,這個中間?只需要把原本雙?通信互發的公鑰,換成??的公鑰,這樣中間?就可以輕松解密通信雙?所發送的所有數據。
* 所以這個時候需要?個安全的第三?頒發證書(CA),證明身份的身份,防?被中間?攻擊。 證書中包括:簽發者、證書?途、使?者公鑰、使?者私鑰、使?者的HASH算法、證書到期時間等。
* 但是問題來了,如果中間?篡改了證書,那么身份證明是不是就?效了?這個證明就?買了,這個時候需要?個新的技術,數字簽名。
* 數字簽名就是?CA?帶的HASH算法對證書的內容進?HASH得到?個摘要,再?CA的私鑰加密,最終組成數字簽名。當別?把他的證書發過來的時候,我再?同樣的Hash算法,再次?成消息摘要,然后?CA的公鑰對數字簽名解密,得到CA創建的消息摘要,兩者??,就知道中間有沒有被?篡改了。這個時候就能最?程度保證通信的安全了。
## 三次握手

三次握手(Three-way Handshake)其實就是指建立一個TCP連接時,需要客戶端和服務器總共發送3個包。進行三次握手的主要作用就是為了確認雙方的接收能力和發送能力是否正常、指定自己的初始化序列號為后面的可靠性傳送做準備。實質上其實就是連接服務器指定端口,建立TCP連接,并同步連接雙方的序列號和確認號,交換TCP窗口大小信息。
剛開始客戶端處于 Closed 的狀態,服務端處于 Listen 狀態。
* 第一次握手:客戶端給服務端發一個 SYN 報文,并指明客戶端的初始化序列號 ISN,此時客戶端處于 SYN\_SEND 狀態。
首部的同步位SYN=1,初始序號seq=x,SYN=1的報文段不能攜帶數據,但要消耗掉一個序號。
* 第二次握手:服務器收到客戶端的 SYN 報文之后,會以自己的 SYN 報文作為應答,并且也是指定了自己的初始化序列號 ISN。同時會把客戶端的 ISN + 1 作為ACK 的值,表示自己已經收到了客戶端的 SYN,此時服務器處于 SYN\_REVD 的狀態。
在確認報文段中SYN=1,ACK=1,確認號ack=x+1,初始序號seq=y
* 第三次握手:客戶端收到 SYN 報文之后,會發送一個 ACK 報文,當然,也是一樣把服務器的 ISN + 1 作為 ACK 的值,表示已經收到了服務端的 SYN 報文,此時客戶端處于 ESTABLISHED 狀態。服務器收到 ACK 報文之后,也處于 ESTABLISHED 狀態,此時,雙方已建立起了連接。
確認報文段ACK=1,確認號ack=y+1,序號seq=x+1(初始為seq=x,第二個報文段所以要+1),ACK報文段可以攜帶數據,不攜帶數據則不消耗序號。
**那為什么要三次握手呢?兩次不行嗎?**
* 為了確認雙方的接收能力和發送能力都正常
* 如果是用兩次握手,則會出現下面這種情況:
如客戶端發出連接請求,但因連接請求報文丟失而未收到確認,于是客戶端再重傳一次連接請求。后來收到了確認,建立了連接。數據傳輸完畢后,就釋放了連接,客戶端共發出了兩個連接請求報文段,其中第一個丟失,第二個到達了服務端,但是第一個丟失的報文段只是在某些網絡結點長時間滯留了,延誤到連接釋放以后的某個時間才到達服務端,此時服務端誤認為客戶端又發出一次新的連接請求,于是就向客戶端發出確認報文段,同意建立連接,不采用三次握手,只要服務端發出確認,就建立新的連接了,此時客戶端忽略服務端發來的確認,也不發送數據,則服務端一致等待客戶端發送數據,浪費資源。
**簡單來說就是以下三步:**
* **第一次握手:** 客戶端向服務端發送連接請求報文段。該報文段中包含自身的數據通訊初始序號。請求發送后,客戶端便進入 SYN-SENT 狀態。
* **第二次握手:** 服務端收到連接請求報文段后,如果同意連接,則會發送一個應答,該應答中也會包含自身的數據通訊初始序號,發送完成后便進入 SYN-RECEIVED 狀態。
* **第三次握手:** 當客戶端收到連接同意的應答后,還要向服務端發送一個確認報文。客戶端發完這個報文段后便進入 ESTABLISHED 狀態,服務端收到這個應答后也進入 ESTABLISHED 狀態,此時連接建立成功。
TCP 三次握手的建立連接的過程就是相互確認初始序號的過程,告訴對方,什么樣序號的報文段能夠被正確接收。 第三次握手的作用是客戶端對服務器端的初始序號的確認。如果只使用兩次握手,那么服務器就沒有辦法知道自己的序號是否 已被確認。同時這樣也是為了防止失效的請求報文段被服務器接收,而出現錯誤的情況。
## 四次揮手

剛開始雙方都處于 ESTABLISHED 狀態,假如是客戶端先發起關閉請求。四次揮手的過程如下:
* 第一次揮手: 客戶端會發送一個 FIN 報文,報文中會指定一個序列號。此時客戶端處于 FIN\_WAIT1 狀態。
即發出連接釋放報文段(FIN=1,序號seq=u),并停止再發送數據,主動關閉TCP連接,進入FIN\_WAIT1(終止等待1)狀態,等待服務端的確認。
* 第二次揮手:服務端收到 FIN 之后,會發送 ACK 報文,且把客戶端的序列號值 +1 作為 ACK 報文的序列號值,表明已經收到客戶端的報文了,此時服務端處于 CLOSE\_WAIT 狀態。
即服務端收到連接釋放報文段后即發出確認報文段(ACK=1,確認號ack=u+1,序號seq=v),服務端進入CLOSE\_WAIT(關閉等待)狀態,此時的TCP處于半關閉狀態,客戶端到服務端的連接釋放。客戶端收到服務端的確認后,進入FIN\_WAIT2(終止等待2)狀態,等待服務端發出的連接釋放報文段。
* 第三次揮手:如果服務端也想斷開連接了,和客戶端的第一次揮手一樣,發給 FIN 報文,且指定一個序列號。此時服務端處于 LAST\_ACK 的狀態。
即服務端沒有要向客戶端發出的數據,服務端發出連接釋放報文段(FIN=1,ACK=1,序號seq=w,確認號ack=u+1),服務端進入LAST\_ACK(最后確認)狀態,等待客戶端的確認。
* 第四次揮手:客戶端收到 FIN 之后,一樣發送一個 ACK 報文作為應答,且把服務端的序列號值 +1 作為自己 ACK 報文的序列號值,此時客戶端處于 TIME\_WAIT 狀態。需要過一陣子以確保服務端收到自己的 ACK 報文之后才會進入 CLOSED 狀態,服務端收到 ACK 報文之后,就處于關閉連接了,處于 CLOSED 狀態。
即客戶端收到服務端的連接釋放報文段后,對此發出確認報文段(ACK=1,seq=u+1,ack=w+1),客戶端進入TIME\_WAIT(時間等待)狀態。此時TCP未釋放掉,需要經過時間等待計時器設置的時間2MSL后,客戶端才進入CLOSED狀態。
**那為什么需要四次揮手呢?**
因為當服務端收到客戶端的SYN連接請求報文后,可以直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連接時,當服務端收到FIN報文時,很可能并不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴客戶端,“你發的FIN報文我收到了”。只有等到我服務端所有的報文都發送完了,我才能發送FIN報文,因此不能一起發送,故需要四次揮手。
**簡單來說就是以下四步:**
* **第一次揮手** :若客戶端認為數據發送完成,則它需要向服務端發送連接釋放請求。
* **第二次揮手**:服務端收到連接釋放請求后,會告訴應用層要釋放 TCP 鏈接。然后會發送 ACK 包,并進入 CLOSE\_WAIT 狀態,此時表明客戶端到服務端的連接已經釋放,不再接收客戶端發的數據了。但是因為 TCP 連接是雙向的,所以服務端仍舊可以發送數據給客戶端。
* **第三次揮手**:服務端如果此時還有沒發完的數據會繼續發送,完畢后會向客戶端發送連接釋放請求,然后服務端便進入 LAST-ACK 狀態。
* **第四次揮手**:客戶端收到釋放請求后,向服務端發送確認應答,此時客戶端進入 TIME-WAIT 狀態。該狀態會持續 2MSL(最大段生存期,指報文段在網絡中生存的時間,超時會被拋棄) 時間,若該時間段內沒有服務端的重發請求的話,就進入 CLOSED 狀態。當服務端收到確認應答后,也便進入 CLOSED 狀態。
TCP 使用四次揮手的原因是因為 TCP 的連接是全雙工的,所以需要雙方分別釋放到對方的連接,單獨一方的連接釋放,只代 表不能再向對方發送數據,連接處于的是半釋放的狀態。
最后一次揮手中,客戶端會等待一段時間再關閉的原因,是為了防止發送給服務器的確認報文段丟失或者出錯,從而導致服務器 端不能正常關閉。
## 對 WebSocket 的理解
* WebSocket是HTML5提供的一種瀏覽器與服務器進行**全雙工通訊**的網絡技術,屬于應用層協議。它基于TCP傳輸協議,并復用HTTP的握手通道。瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創建持久性的連接, 并進行雙向數據傳輸。
* WebSocket 的出現就解決了半雙工通信的弊端。它最大的特點是:**服務器可以向客戶端主動推動消息,客戶端也可以主動向服務器推送消息。
* **WebSocket原理**:客戶端向 WebSocket 服務器通知(notify)一個帶有所有接收者ID(recipients IDs)的事件(event),服務器接收后立即通知所有活躍的(active)客戶端,只有ID在接收者ID序列中的客戶端才會處理這個事件。
* **WebSocket 特點的如下:**
* 支持雙向通信,實時性更強
* 可以發送文本,也可以發送二進制數據‘’
* 建立在TCP協議之上,服務端的實現比較容易
* 數據格式比較輕量,性能開銷小,通信高效
* 沒有同源限制,客戶端可以與任意服務器通信
* 協議標識符是ws(如果加密,則為wss),服務器網址就是 URL
* 與 HTTP 協議有著良好的兼容性。默認端口也是80和443,并且握手階段采用 HTTP 協議,因此握手時不容易屏蔽,能通過各種 HTTP 代理服務器。
* 代碼
```
// 在index.html中直接寫WebSocket,設置服務端的端口號為 9999
let ws = new WebSocket('ws://localhost:9999');
// 在客戶端與服務端建立連接后觸發
ws.onopen = function() {
console.log("Connection open.");
ws.send('hello');
};
// 在服務端給客戶端發來消息的時候觸發
ws.onmessage = function(res) {
console.log(res); // 打印的是MessageEvent對象
console.log(res.data); // 打印的是收到的消息
};
// 在客戶端與服務端建立關閉后觸發
ws.onclose = function(evt) {
console.log("Connection closed.");
};
```
- 首頁
- 2021年
- 基礎知識
- 同源策略
- 跨域
- css
- less
- scss
- reset
- 超出文本顯示省略號
- 默認滾動條
- 清除浮動
- line-height與vertical-align
- box-sizing
- 動畫
- 布局
- JavaScript
- 設計模式
- 深淺拷貝
- 排序
- canvas
- 防抖節流
- 獲取屏幕/可視區域寬高
- 正則
- 重繪重排
- rem換算
- 手寫算法
- apply、call和bind原理與實現
- this的理解-普通函數、箭頭函數
- node
- nodejs
- express
- koa
- egg
- 基于nodeJS的全棧項目
- 小程序
- 常見問題
- ec-canvas之橫豎屏切換重繪
- 公眾號后臺基本配置
- 小程序發布協議更新
- 小程序引入iconfont字體
- Uni-app
- 環境搭建
- 項目搭建
- 數據庫
- MySQL數據庫安裝
- 數據庫圖形化界面常用命令行
- cmd命令行操作數據庫
- Redis安裝
- APP
- 控制縮放meta
- GIT
- 常用命令
- vsCode
- 常用插件
- Ajax
- axios-services
- 文章
- 如何讓代碼更加優雅
- 虛擬滾動
- 網站收藏
- 防抖節流之定時器清除問題
- 號稱破解全網會員的腳本
- 資料筆記
- 資料筆記2
- 公司面試題
- 服務器相關
- 前端自動化部署-jenkins
- nginx.conf配置
- https添加證書
- shell基本命令
- 微型ssh-deploy前端部署插件
- webpack
- 深入理解loader
- 深入理解plugin
- webpack注意事項
- vite和webpack區別
- React
- react+antd搭建
- Vue
- vue-cli
- vue.config.js
- 面板分割左右拖動
- vvmily-admin-template
- v-if與v-for那個優先級高?
- 下載excel
- 導入excel
- Echart-China-Map
- vue-xlsx(解析excel)
- 給elementUI的el-table添加骨架
- cdn引入配置
- Vue2.x之defineProperty應用
- 徹底弄懂diff算法的key作用
- 復制模板內容
- 表格操作按鈕太多
- element常用組件二次封裝
- Vue3.x
- Vue3快速上手(第一天)
- Vue3.x快速上手(第二天)
- Vue3.x快速上手(第三天)
- vue3+element-plus搭建項目
- vue3
- 腳手架
- vvmily-cli
- TS
- ts筆記
- common
- Date
- utils
- axios封裝
- 2022年
- HTML
- CSS基礎
- JavaScript 基礎
- 前端框架Vue
- 計算機網絡
- 瀏覽器相關
- 性能優化
- js手寫代碼
- 前端安全
- 前端算法
- 前端構建與編譯
- 操作系統
- Node.js
- 一些開放問題、智力題