有了 HTTP 協議,為什么還需要 Websocket?
WebSocket 是一種基于 TCP 連接上進行全雙工通信的協議,相對于 HTTP 這種非持久的協議來說,WebSocket 是一個持久化網絡通信的協議。
它不僅可以實現客戶端請求服務器,同時可以允許服務端主動向客戶端推送數據。在 WebSocket API 中,客戶端和服務器只需要完成一次握手,兩者之間就直接可以創建持久性的連接,并進行雙向數據傳輸。
為什么需要 WebSocket
在 Web 應用架構中,連接由 HTTP/1.0 和 HTTP/1.1 處理。HTTP 是客戶端/服務器模式中 請求一響應 所用的協議,在這種模式中,客戶端(一般是瀏覽器)向服務器提交 HTTP 請求,服務器響應請求的資源(例如 HTML 頁面)。
HTTP 是無狀態的,也就是說,它將每個請求當成唯一和獨立的。無狀態協議具有一些優勢,例如,服務器不需要保存有關會話的信息,從而不需要存儲數據。但是,這也意味著在每次 HTTP 請求和響應中都會發送關于請求的冗余信息,比如使用 Cookie 進行用戶狀態的驗證。
隨著客戶端和服務器之間交互的增加,HTTP 協議在客戶端和服務器之間通信所需要的信息量快速增加。
從根本上講,HTTP 還是 半雙工 的協議,也就是說,在同一時刻信息的流向只能單向的:客戶端向服務器發送請求(單向),然后服務器響應請求(單向)。半雙工方式的通信效率是非常低的。
同時 HTTP 協議有一個缺陷:通信只能由客戶端發起。
這種單向請求的特點,注定了如果服務器有狀態變化,是無法主動通知客戶端的。
為了能夠及時的獲取服務器的變化,我們嘗試過各種各樣的方式:
- 輪詢(polling):每隔一段時間,就發出一個請求,了解服務器有沒有新的信息。不精準,有延時,大量無效數據交換。
- 長輪詢( long polling):客戶端向服務器請求信息,并在設定的時間段內保持連接。直到服務器有新消息響應,或者連接超時,這種技術常常稱作“掛起GET”或“擱置POST”。占用服務器資源,相對輪詢并沒有優勢,沒有標準化。
- 流化技術:在流化技術中,客戶端發送一個請求,服務器發送并維護一個持續更新和保持打開(可以是無限或者規定的時間段)的開放響應。每當服務器有需要交付給客戶端的信息時,它就更新響應。服務器從不發出完成 HTTP 響應。代理和防火墻可能緩存響應,導致信息交付的延遲增加。
上述方法提供了近乎實時的通信,但是它們也涉及 HTTP 請求和響應首標,包含了許多附加和不必要的首標數據與延遲。此外,在每一種情況下,客戶端都必須等待請求返回,才能發出后續的請求,而這顯著地增加了延退。同時也極大地增加了服務器的壓力。
什么是 WebSocket
而 Websocket 是一種自然的全雙工、雙向、單套接字連接,解決了 HTTP 協議中不適合于實時通信的問題。2008 年被提出,2011 年成為國際標準。
Websocket 協議能夠通過 Web 進行客戶端和服務器之間的全雙工通信,并支持二進制數據和文本字符串的傳輸。
這個協議由開始的握手和之后的基本消息框架組成,是建立在 TCP 協議上的。相比于 HTTP 協議,Websocket 鏈接一旦建立,即可進行雙向的實時通信。
其特點包括:
(1)建立在 TCP 協議之上,服務器端的實現比較容易。
(2)與 HTTP 協議有著良好的兼容性。默認端口也是 80 和 443,并且握手階段采用 HTTP 協議,因此握手時不容易屏蔽,能通過各種 HTTP 代理服務器。
(3)數據格式比較輕量,性能開銷小,通信高效。
(4)可以發送文本,也可以發送二進制數據。
(5)沒有同源限制,客戶端可以與任意服務器通信。
相似技術
Server-sent Events(SSE):
https://www.ruanyifeng.com/blog/2017/05/server-sent_events.html
https://www.cnblogs.com/goloving/p/9196066.html
SPDY (讀作“SPeeDY”):已不再維護,由 HTTP/2 取代
https://baike.baidu.com/item/SPDY/3399551#7
WebRTC
https://baike.baidu.com/item/WebRTC/5522744
通信原理
WebSocket 鏈接是如何建立的?
前面說過,WebSocket 在握手階段采用的是 HTTP 協議,Websocket 借用了 HTTP 的一部分協議來完成一次握手。(HTTP的三次握手,此處只完成一次)
HTTP 請求與響應首部
WebSocket 請求與響應首部
鏈接通信模擬
HTTP 輪詢
首先是 ajax 輪詢,其原理非常簡單,讓瀏覽器隔個幾秒就發送一次請求,詢問服務器是否有新信息。
場景再現:
- 客戶端:啦啦啦,有沒有新信息(Request)
- 服務端:沒有(Request)
- 客戶端:啦啦啦,有沒有新信息(Request)
- 服務端:沒有。。(Response)
- 客戶端:啦啦啦,有沒有新信息(Request)
- 服務端:你好煩啊,沒有啊。。(Response)
- 客戶端:啦啦啦,有沒有新消息(Request)
- 服務端:好啦好啦,有啦給你 ' 西嶺真帥' 。(Response)
- 客戶端:啦啦啦,有沒有新消息(Request)
- 服務端:。。。沒。。。。沒。。沒有
從上面可以看出,輪詢其實就是在不斷地建立HTTP連接,然后等待服務端處理,可以體現 HTTP 協議的另外一個特點,被動性。同時,http 的每一次請求與響應結束后,服務器將客戶端信息全部丟棄,下次請求,必須攜帶身份信息(cookie),無狀態性。
WebSocket
客戶端通過 http(騎馬)帶著信請求服務器,但同時,攜帶了 Upgrade:websocket 和Connection:Upgrade(兩根管子),服務器如果支持 WebSocket 協議(有兩根管子的接口),使用 Websocket 協議返回可用信息(丟棄馬匹),此后信息的傳遞,均使用這兩個管子,除非有一方人為的將管子切斷。若服務器不支持,客戶端請求鏈接失敗,返回錯誤信息。
Websocket 的出現,干凈利落的解決了這些問題。
所以上面的情景可以做如下修改。
- 客戶端:啦啦啦,我要建立 Websocket 協議,需要的服務:chat,Websocket協議版本:13(HTTP Request)
- 服務端:ok,確認,已升級為 Websocket協議(HTTP Protocols Switched)
- 客戶端:麻煩你有信息的時候推送給我噢。。
- 服務端:ok,有的時候會告訴你的。
- 客戶端:balabala開始斗圖balabala
- 服務端:蒼*空bala
- 客戶端:流鼻血了,我擦……
- 服務端:哈哈哈牛XX啊哈哈哈哈
- 服務端:笑死我了哈哈
本文轉載自微信公眾號「勾勾的前端世界」





































