WebSocket 是什麼?爲什麼能持久連接?
一、WebSocket 是什麼
WebSocket,是一種網絡傳輸協議,位於 OSI 模型的應用層。可在單個 TCP 連接上進行全雙工通信,能更好的節省服務器資源和帶寬並達到實時通迅 客戶端和服務器只需要完成一次握手,兩者之間就可以創建持久性的連接,並進行雙向數據傳輸
二、特點
全雙工 通信允許數據在兩個方向上同時傳輸,它在能力上相當於兩個單工通信方式的結合 例如指 A→B 的同時 B→A ,是瞬時同步的 二進制幀 採用了二進制幀結構,語法、語義與 HTTP 完全不兼容,相比 http/2,WebSocket 更側重於 “實時通信”,而 HTTP/2 更側重於提高傳輸效率,所以兩者的幀結構也有很大的區別 不像 HTTP/2 那樣定義流,也就不存在多路複用、優先級等特性 自身就是全雙工,也不需要服務器推送 協議名 引入 ws 和 wss 分別代表明文和密文的 websocket 協議,且默認端口使用 80 或 443,幾乎與 http 一致
ws://www.chrono.com
ws://www.chrono.com:8080/srv
ws://www.chrono.com:445/im?user=user_id=xxxx
握手 WebSocket 也要有一個握手過程,然後才能正式收發數據 客戶端發送數據格式如下:
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Origin: http://example.com Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13
服務端返回的數據格式:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=Sec-WebSocket-Protocol: chat
HTTP/1.1 101 Switching Protocols:表示服務端接受 WebSocket 協議的客戶端連接
- Sec-WebSocket-Accep:驗證客戶端請求報文,同樣也是爲了防止誤連接。具體做法是把請求頭裏 “Sec-WebSocket-Key” 的值,加上一個專用的 UUID,再計算摘要
優點
-
較少的控制開銷:數據包頭部協議較小,不同於 http 每次請求需要攜帶完整的頭部
-
更強的實時性:相對於 HTTP 請求需要等待客戶端發起請求服務端才能響應,延遲明顯更少
-
保持創連接狀態:創建通信後,可省略狀態信息,不同於 HTTP 每次請求需要攜帶身份驗證
-
更好的二進制支持:定義了二進制幀,更好處理二進制內容
-
支持擴展:用戶可以擴展 websocket 協議、實現部分自定義的子協議
-
更好的壓縮效果:Websocket 在適當的擴展支持下,可以沿用之前內容的上下文,在傳遞類似的數據時,可以顯著地提高壓縮率
HTTP 協議的 “缺陷”
瞭解 http 的人都知道,HTTP 協議有一個缺陷:通信只能由客戶端發起。例如,我們想了解今天的天氣,只能是客戶端向服務器發出請求,服務器返回查詢結果。HTTP 協議做不到服務器主動向客戶端推送信息的, 這種單向請求的特點,註定瞭如果服務器有連續的狀態變化,客戶端要獲知就非常麻煩,客戶端只能使用” 輪詢” 的方式,即每隔一段時間,就發出一個請求,請求服務器有沒有狀態變化 。可見輪詢的效率低,非常浪費資源。
在 http1.1 中,默認開啓了一個叫 Keep-alive 的參數,官方的說法是可以用這個來作爲長連接。你是否以爲既然客戶端與服務器保持了長連接,服務器就能主動給客戶端推送消息呢?
關於 Keep-alive 的缺點
Keep-alive 的確可以實現長連接,但是這個長連接是有問題的,本質上依然是客戶端主動發起 - 服務端應答的模式,是沒法做到服務端主動發送通知給客戶端的。也就是說,在一個 HTTP 連接中,客戶端可以發送多個 Request,接收多個 Response。但是請記住 Request = Response , 在 HTTP 中永遠是這樣,一個 request 只能有一個 response。而且這個 response 也是被動的,不能主動發起。放上一張圖,圖左爲沒開啓 Keep-alive,圖右爲開啓了 Keep-alive,可以看出依然是一問一答的模式,向較左邊只是省略了每次的關閉和打開操作。
需要注意的是 Keep-alive 是指不需要多次建立連接,而非 http2.0 裏面的多路複用,多路複用的意思是客戶端可以同時向服務器端發送多個請求,服務器端也可以同時響應多個 Response.
關於 websocket
那麼如果我們需要服務器狀態變化的時候能夠主動通知客戶端,我們有沒有什麼辦法呢?這就要用到 websocket。
上圖對比可以看出,相對於傳統 HTTP 每次請求 - 應答都需要客戶端與服務端建立連接的模式,WebSocket 是類似 Socket 的 TCP 長連接的通訊模式,一旦 WebSocket 連接建立後,後續數據都以幀序列的形式傳輸。在客戶端斷開 WebSocket 連接或 Server 端斷掉連接前,不需要客戶端和服務端重新發起連接請求。在海量併發及客戶端與服務器交互負載流量大的情況下,極大的節省了網絡帶寬資源的消耗,有明顯的性能優勢,且客戶端發送和接受消息是在同一個持久連接上發起,實時性優勢明顯。
WebSocket API 是 HTML5 標準的一部分, 但這並不代表 WebSocket 一定要用在 HTML 中,或者只能在基於瀏覽器的應用程序中使用。
在 WebSocket 中,只需要服務器和瀏覽器通過 TCP 協議進行一個握手的動作,然後單獨建立一條 TCP 的通信通道進行數據的傳送。WebSocket 同 HTTP 一樣也是應用層的協議,但是它是一種雙向通信協議,是建立在 TCP 之上的。websocket 的流程大概是以下幾步:
1、瀏覽器、服務器建立 TCP 連接,三次握手。這是通信的基礎,傳輸控制層,若失敗後續都不執行。2、TCP 連接成功後,瀏覽器通過 HTTP 協議向服務器傳送 WebSocket 支持的版本號等信息。(開始前的 HTTP 握手) 3、服務器收到客戶端的握手請求後,同樣採用 HTTP 協議回饋數據。4、當收到了連接成功的消息後,通過 TCP 通道進行傳輸通信。
也就是說 WebSocket 在建立握手時,數據是通過 HTTP 傳輸的。但是建立之後,在真正傳輸時候是不需要 TCP 協議的。
看看一次 websocket 的握手請求與應答的報文
WebSocket 客戶端連接報文
GET /webfin/websocket/ HTTP/1.1 Host: localhost Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg== Origin: http://localhost :8080 Sec-WebSocket-Version: 13
可以看到,客戶端發起的 WebSocket 連接報文類似傳統 HTTP 報文,”Upgrade:websocket”參數值表明這是 WebSocket 類型請求,“Sec-WebSocket-Key”是 WebSocket 客戶端發送的一個 base64 編碼的密文,要求服務端必須返回一個對應加密的 “Sec-WebSocket-Accept” 應答,否則客戶端會拋出 “Error during WebSocket handshake” 錯誤,並關閉連接。
服務端收到報文後返回的數據格式類似:
WebSocket 服務端響應報文
GET /webfin/websocket/ HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==
Origin:
http://localhost
:8080
Sec-WebSocket-Version: 13
“Sec-WebSocket-Accept” 的值是服務端採用與客戶端一致的密鑰計算出來後返回客戶端的,“HTTP/1.1 101 Switching Protocols” 表示服務端接受 WebSocket 協議的客戶端連接,經過這樣的請求 - 響應處理後,客戶端服務端的 WebSocket 連接握手成功, 後續就可以進行 TCP 通訊了。
WebSocket 與 Socket 的關係
Socket 其實並不是一個協議,而是爲了方便使用 TCP 或 UDP 而抽象出來的一層,是位於應用層和傳輸控制層之間的一組接口。
Socket 是應用層與 TCP/IP 協議族通信的中間軟件抽象層,它是一組接口。在設計模式中,Socket 其實就是一個門面模式,它把複雜的 TCP/IP 協議族隱藏在 Socket 接口後面,對用戶來說,一組簡單的接口就是全部,讓 Socket 去組織數據,以符合指定的協議。
當兩臺主機通信時,必須通過 Socket 連接,Socket 則利用 TCP/IP 協議建立 TCP 連接。TCP 連接則更依靠於底層的 IP 協議,IP 協議的連接則依賴於鏈路層等更低層次。
WebSocket 則是一個典型的應用層協議。
WebSocket 與 HTTP
WebSocket 協議在 2008 年誕生,2011 年成爲國際標準。現在所有瀏覽器都已經支持了。WebSocket 的最大特點就是,服務器可以主動向客戶端推送信息,客戶端也可以主動向服務器發送信息,是真正的雙向平等對話。
HTTP 有 1.1 和 1.0 之說,也就是所謂的 keep-alive ,把多個 HTTP 請求合併爲一個,但是 Websocket 其實是一個新協議,跟 HTTP 協議基本沒有關係,只是爲了兼容現有瀏覽器,所以在握手階段使用了 HTTP 。
下面一張圖說明了 HTTP 與 WebSocket 的主要區別:
WebSocket 的其他特點:
-
建立在 TCP 協議之上,服務器端的實現比較容易。
-
與 HTTP 協議有着良好的兼容性。默認端口也是 80 和 443,並且握手階段採用 HTTP 協議,因此握手時不容易屏蔽,能通過各種 HTTP 代理服務器。
-
數據格式比較輕量,性能開銷小,通信高效。
-
可以發送文本,也可以發送二進制數據。
-
沒有同源限制,客戶端可以與任意服務器通信。
-
協議標識符是 ws(如果加密,則爲 wss),服務器網址就是 URL。
WebSocket 原理及如何實現長連接
websocket 相當於 HTTP 的一個補充協議,通過 http request 建立連接,不需要再發送 request,之後保持一端與另外一端的 TCP 連接。
在實際應用中,一個 socket 與另外一端的連接可能會經過千山萬水(多個路由、多箇中間服務器),中間有各種轉發、過濾。
所以後來更新了,添加了 Ping/Pong Frame(RFC 6455 - The WebSocket Protocol),可以說這是一個特殊的數據包,
這個數據包只有簡單的一些的元數據,不涉及數據傳輸。維持連接的活躍性與持久性。
參考文獻
-
httpss://zh.wikipedia.org/wiki/WebSocket
-
httpss://www.oschina.net/translate/9-killer-uses-for-websockets
-
httpss://vue3js.cn/interview
-
httpss://www.cnblogs.com/Javi/p/9303020.html
-
httpss//blog.csdn.net/qq_35447305/article/details/52966105
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/1ZdDvHSntrLuLQgdCZxqcw