WebSocket 是什麼原理?為什麼可以實現持久連線?有點懵!!!

程丞橙發表於2020-09-27

一、WebSocket是HTML5出的東西(協議),也就是說HTTP協議沒有變化,或者說沒關係,但HTTP是不支援持久連線的(長連線,迴圈連線的不算)首先HTTP有1.1和1.0之說,也就是所謂的keep-alive,把多個HTTP請求合併為一個,但是Websocket其實是一個新協議,跟HTTP協議基本沒有關係,只是為了相容現有瀏覽器的握手規範而已,也就是說它是HTTP協議上的一種補充可以通過這樣一張圖理解
在這裡插入圖片描述有交集,但是並不是全部。
另外Html5是指的一系列新的API,或者說新規範,新技術。Http協議本身只有1.0和1.1,而且跟Html本身沒有直接關係。。
通俗來說,你可以用HTTP協議傳輸非Html資料,就是這樣=。=
再簡單來說,層級不一樣。
二、Websocket是什麼樣的協議,具體有什麼優點
首先,Websocket是一個持久化的協議,相對於HTTP這種非持久的協議來說。
簡單的舉個例子吧,用目前應用比較廣泛的PHP生命週期來解釋。

  1. HTTP的生命週期通過Request來界定,也就是一個Request 一個Response,那麼在HTTP1.0中,這次HTTP請求就結束了。
    在HTTP1.1中進行了改進,使得有一個keep-alive,也就是說,在一個HTTP連線中,可以傳送多個Request,接收多個Response。
    但是請記住 Request = Response , 在HTTP中永遠是這樣,也就是說一個request只能有一個response。而且這個response也是被動的,不能主動發起。
    教練,你BB了這麼多,跟Websocket有什麼關係呢?
    _(:з」∠)_好吧,我正準備說Websocket呢。。
    首先Websocket是基於HTTP協議的,或者說 借用了HTTP的協議來完成一部分握手。
    在握手階段是一樣的
    -------以下涉及專業技術內容,不想看的可以跳過lol:,或者只看加黑內容--------
    首先我們來看個典型的Websocket握手(借用Wikipedia的。。)

熟悉HTTP的童鞋可能發現了,這段類似HTTP協議的握手請求中,多了幾個東西。
我會順便講解下作用。

Upgrade: websocket

Connection: Upgrade

這個就是Websocket的核心了,告訴Apache、Nginx等伺服器: 注意啦,窩發起的是Websocket協議,快點幫我找到對應的助理處理~不是那個老土的HTTP。

Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==

Sec-WebSocket-Protocol: chat, superchat

Sec-WebSocket-Version: 13

首先,Sec-WebSocket-Key 是一個Base64 encode的值,這個是瀏覽器隨機生成的,告訴伺服器:泥煤,不要忽悠窩,我要驗證尼是不是真的是Websocket助理。
然後,Sec_WebSocket-Protocol 是一個使用者定義的字串,用來區分同URL下,不同的服務所需要的協議。簡單理解:今晚我要服務A,別搞錯啦~
最後,Sec-WebSocket-Version 是告訴伺服器所使用的Websocket Draft(協議版本),在最初的時候,Websocket協議還在 Draft 階段,各種奇奇怪怪的協議都有,而且還有很多期奇奇怪怪不同的東西,什麼Firefox和Chrome用的不是一個版本之類的,當初Websocket協議太多可是一個大難題。。不過現在還好,已經定下來啦大家都使用的一個東西 脫水:服務員,我要的是13歲的噢→_→
然後伺服器會返回下列東西,表示已經接受到請求, 成功建立Websocket啦!

HTTP/1.1 101 Switching Protocols

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

Sec-WebSocket-Protocol: chat

這裡開始就是HTTP最後負責的區域了,告訴客戶,我已經成功切換協議啦~

Upgrade: websocket

Connection: Upgrade

依然是固定的,告訴客戶端即將升級的是Websocket協議,而不是mozillasocket,lurnarsocket或者shitsocket。
然後,Sec-WebSocket-Accept 這個則是經過伺服器確認,並且加密過後的 Sec-WebSocket-Key。伺服器:好啦好啦,知道啦,給你看我的ID CARD來證明行了吧。。
後面的,Sec-WebSocket-Protocol 則是表示最終使用的協議。

至此,HTTP已經完成它所有工作了,接下來就是完全按照Websocket協議進行了。
具體的協議就不在這闡述了。
------------------技術解析部分完畢------------------
在這裡插入圖片描述
你TMD又BBB了這麼久,那到底Websocket有什麼鬼用,http long poll,或者ajax輪詢不都可以實現實時資訊傳遞麼。
在這裡插入圖片描述
三、Websocket的作用
在講Websocket之前,我就順帶著講下 long poll 和 ajax輪詢 的原理。
首先是 ajax輪詢 ,ajax輪詢 的原理非常簡單,讓瀏覽器隔個幾秒就傳送一次請求,詢問伺服器是否有新資訊。
場景再現:
客戶端:啦啦啦,有沒有新資訊(Request)
服務端:沒有(Response)
客戶端:啦啦啦,有沒有新資訊(Request)
服務端:沒有。。(Response)
客戶端:啦啦啦,有沒有新資訊(Request)
服務端:你好煩啊,沒有啊。。(Response)
客戶端:啦啦啦,有沒有新訊息(Request)
服務端:好啦好啦,有啦給你。(Response)
客戶端:啦啦啦,有沒有新訊息(Request)
服務端:。。。。。沒。。。。沒。。。沒有(Response) ---- loop

long poll
long poll 其實原理跟 ajax輪詢 差不多,都是採用輪詢的方式,不過採取的是阻塞模型(一直打電話,沒收到就不掛電話),也就是說,客戶端發起連線後,如果沒訊息,就一直不返回Response給客戶端。直到有訊息才返回,返回完之後,客戶端再次建立連線,周而復始。
場景再現
客戶端:啦啦啦,有沒有新資訊,沒有的話就等有了才返回給我吧(Request)
服務端:額。。 等待到有訊息的時候。。來 給你(Response)
客戶端:啦啦啦,有沒有新資訊,沒有的話就等有了才返回給我吧(Request) -loop

從上面可以看出其實這兩種方式,都是在不斷地建立HTTP連線,然後等待服務端處理,可以體現HTTP協議的另外一個特點:被動性。
何為被動性呢,其實就是,服務端不能主動聯絡客戶端,只能有客戶端發起。
簡單地說就是,伺服器是一個很懶的冰箱(這是個梗)(不會、不能主動發起連線),但是上司有命令,如果有客戶來,不管多麼累都要好好接待。

說完這個,我們再來說一說上面的缺陷(原諒我廢話這麼多吧OAQ)
從上面很容易看出來,不管怎麼樣,上面這兩種都是非常消耗資源的。
ajax輪詢 需要伺服器有很快的處理速度和資源。(速度)
long poll 需要有很高的併發,也就是說同時接待客戶的能力。(場地大小)
所以ajax輪詢 和long poll 都有可能發生這種情況。

客戶端:啦啦啦啦,有新資訊麼?
服務端:月線正忙,請稍後再試(503 Server Unavailable)
客戶端:。。。。好吧,啦啦啦,有新資訊麼?
服務端:月線正忙,請稍後再試(503 Server Unavailable)

客戶端:
在這裡插入圖片描述
然後服務端在一旁忙的要死:冰箱,我要更多的冰箱!更多。。更多。。(我錯了。。這又是梗。。)


言歸正傳,我們來說Websocket吧
通過上面這個例子,我們可以看出,這兩種方式都不是最好的方式,需要很多資源。
一種需要更快的速度,一種需要更多的’電話’。這兩種都會導致’電話’的需求越來越高。
哦對了,忘記說了HTTP還是一個無狀態協議。(感謝評論區的各位指出OAQ)
通俗的說就是,伺服器因為每天要接待太多客戶了,是個***健忘鬼***,你一掛電話,他就把你的東西全忘光了,把你的東西全丟掉了。你第二次還得再告訴伺服器一遍。

所以在這種情況下出現了,Websocket出現了。
他解決了HTTP的這幾個難題。
首先,被動性,當伺服器完成協議升級後(HTTP->Websocket),服務端就可以主動推送資訊給客戶端啦。
所以上面的情景可以做如下修改。
客戶端:啦啦啦,我要建立Websocket協議,需要的服務:chat,Websocket協議版本:17(HTTP Request)
服務端:ok,確認,已升級為Websocket協議(HTTP Protocols Switched)
客戶端:麻煩你有資訊的時候推送給我噢。。
服務端:ok,有的時候會告訴你的。
服務端:balabalabalabala
服務端:balabalabalabala
服務端:哈哈哈哈哈啊哈哈哈哈
服務端:笑死我了哈哈哈哈哈哈哈

就變成了這樣,只需要經過一次HTTP請求,就可以做到源源不斷的資訊傳送了。(在程式設計中,這種設計叫做回撥,即:你有資訊了再來通知我,而不是我傻乎乎的每次跑來問你)
這樣的協議解決了上面同步有延遲,而且還非常消耗資源的這種情況。
那麼為什麼他會解決伺服器上消耗資源的問題呢?
其實我們所用的程式是要經過兩層代理的,即HTTP協議在Nginx等伺服器的解析下,然後再傳送給相應的Handler(PHP等)來處理。
簡單地說,我們有一個***非常快速的接線員(Nginx)***,他負責把問題轉交給***相應的客服(Handler)**
本身接線員基本上速度是足夠的,但是每次都卡在
客服(Handler)了,老有客服處理速度太慢,導致客服不夠。
Websocket就解決了這樣一個難題,建立後,可以直接跟接線員建立持久連線,有資訊的時候客服想辦法通知接線員,然後接線員在統一轉交給客戶。
這樣就可以解決客服處理速度過慢的問題了。
同時,在傳統的方式上,要不斷的建立,關閉HTTP協議,由於HTTP是非狀態性的,每次都要 重新傳輸identity info(鑑別資訊),來告訴服務端你是誰。
雖然接線員很快速,但是每次都要聽這麼一堆,效率也會有所下降的,同時還得不斷把這些資訊轉交給客服,不但浪費客服的 處理時間,而且還會在網路傳輸中消耗 過多的流量/時間。
但是Websocket只需要 一次HTTP握手,所以說整個通訊過程是建立在一次連線/狀態中,也就避免了HTTP的非狀態性,服務端會一直知道你的資訊,直到你關閉請求,這樣就解決了接線員要反覆解析HTTP協議,還要檢視identity info的資訊。
同時由 客戶主動詢問,轉換為 伺服器(推送)有資訊的時候就傳送(當然客戶端還是等主動傳送資訊過來的。),沒有資訊的時候就交給接線員(Nginx),不需要佔用本身速度就慢的 客服(Handler)了
--------------------

至於怎麼在不支援Websocket的客戶端上使用Websocket。。答案是: 不能
但是可以通過上面說的 long poll 和 ajax 輪詢來 模擬出類似的效果
-----

以下是騰訊雲技術社群整理的 WebSocket原理說明 ——

眾所周知,Web應用的通訊過程通常是客戶端通過瀏覽器發出一個請求,伺服器端接收請求後進行處理並返回結果給客戶端,客戶端瀏覽器將資訊呈現。這種機制對於資訊變化不是特別頻繁的應用可以良好支撐,但對於實時要求高、海量併發的應用來說顯得捉襟見肘,尤其在當前業界移動網際網路蓬勃發展的趨勢下,高併發與使用者實時響應是Web應用經常面臨的問題,比如金融證券的實時資訊、Web導航應用中的地理位置獲取、社交網路的實時訊息推送等。

傳統的請求-響應模式的Web開發在處理此類業務場景時,通常採用實時通訊方案。比如常見的輪詢方案,其原理簡單易懂,就是客戶端以一定的時間間隔頻繁請求的方式向伺服器傳送請求,來保持客戶端和伺服器端的資料同步。其問題也很明顯:當客戶端以固定頻率向伺服器端傳送請求時,伺服器端的資料可能並沒有更新,帶來很多無謂請求,浪費頻寬,效率低下。

基於Flash,AdobeFlash通過自己的Socket實現完成資料交換,再利用Flash暴露出相應的介面給JavaScript呼叫,從而達到實時傳輸目的。此方式比輪詢要高效,且因為Flash安裝率高,應用場景廣泛。然而,移動網際網路終端上Flash的支援並不好:IOS系統中無法支援Flash,Android雖然支援Flash但實際的使用效果差強人意,且對移動裝置的硬體配置要求較高。2012年Adobe官方宣佈不再支援Android4.1+系統,宣告了Flash在移動終端上的死亡。

傳統的Web模式在處理高併發及實時性需求的時候,會遇到難以逾越的瓶頸,需要一種高效節能的雙向通訊機制來保證資料的實時傳輸。在此背景下,基於HTML5規範的、有Web TCP之稱的 WebSocket應運而生。早期HTML5並沒有形成業界統一的規範,各個瀏覽器和應用伺服器廠商有著各異的類似實現,如IBM的MQTT、Comet開源框架等。直到2014年,HTML5終於塵埃落地,正式落實為實際標準規範,各個應用伺服器及瀏覽器廠商逐步開始統一,在 JavaEE7中也實現了WebSocket協議。至此無論是客戶端還是服務端的WebSocket都已完備。使用者可以查閱HTML5規範,熟悉新的HTML協議規範及WebSocket支援。

WebSocket 機制

以下簡要介紹一下WebSocket的原理及執行機制。

WebSocket是HTML5下一種新的協議。它實現了瀏覽器與伺服器全雙工通訊,能更好的節省伺服器資源和頻寬並達到實時通訊的目的。它與HTTP一樣通過已建立的TCP連線來傳輸資料,但是它和HTTP最大不同是:

  • WebSocket是一種雙向通訊協議。在建立連線後,WebSocket伺服器端和客戶端都能主動向對方傳送或接收資料,就像Socket一樣;
  • WebSocket需要像TCP一樣,先建立連線,連線成功後才能相互通訊。

傳統HTTP客戶端與伺服器請求響應模式如下圖所示:
在這裡插入圖片描述

WebSocket模式客戶端與伺服器請求響應模式如下圖:
在這裡插入圖片描述上圖對比可以看出,相對於傳統HTTP每次請求-應答都需要客戶端與服務端建立連線的模式,WebSocket是類似Socket的TCP長連線通訊模式。一旦WebSocket連線建立後,後續資料都以幀序列的形式傳輸。在客戶端斷開WebSocket連線或Server端中斷連線前,不需要客戶端和服務端重新發起連線請求。在海量併發及客戶端與伺服器互動負載流量大的情況下,極大的節省了網路頻寬資源的消耗,有明顯的效能優勢,且客戶端傳送和接受訊息是在同一個持久連線上發起,實時性優勢明顯。

相比HTTP長連線,WebSocket有以下特點:

  • 是真正的全雙工方式,建立連線後客戶端與伺服器端是完全平等的,可以互相主動請求。而HTTP長連線基於HTTP,是傳統的客戶端對伺服器發起請求的模式。
  • HTTP長連線中,每次資料交換除了真正的資料部分外,伺服器和客戶端還要大量交換HTTP
    header,資訊交換效率很低。Websocket協議通過第一個request建立了TCP連線之後,之後交換的資料都不需要傳送 HTTP header就能交換資料,這顯然和原有的HTTP協議有區別所以它需要對伺服器和客戶端都進行升級才能實現(主流瀏覽器都已支援HTML5)。此外還有multiplexing、不同的URL可以複用同一個WebSocket連線等功能。這些都是HTTP長連線不能做到的。

下面再通過客戶端和服務端互動的報文對比WebSocket通訊與傳統HTTP的不同點:

在客戶端,new WebSocket例項化一個新的WebSocket客戶端物件,請求類似 ws://yourdomain:port/path 的服務端WebSocket URL,客戶端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錯誤,並關閉連線。

服務端收到報文後返回的資料格式類似:

HTTP/1.1 101 Switching Protocols

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=

Sec-WebSocket-Accept的值是服務端採用與客戶端一致的金鑰計算出來後返回客戶端的,HTTP/1.1 101 Switching Protocols表示服務端接受WebSocket協議的客戶端連線,經過這樣的請求-響應處理後,兩端的WebSocket連線握手成功, 後續就可以進行TCP通訊了。使用者可以查閱WebSocket協議棧瞭解WebSocket客戶端和服務端更詳細的互動資料格式。

在開發方面,WebSocket API 也十分簡單:只需要例項化 WebSocket,建立連線,然後服務端和客戶端就可以相互傳送和響應訊息。在WebSocket 實現及案例分析部分可以看到詳細的 WebSocket API 及程式碼實現。

騰訊雲公網有日租型別七層負載均衡轉發部分支援Websocket,目前包括英魂之刃、銀漢遊戲等多家企業已接入使用。當出現不相容問題時,請修改websocket配置,websocket server不校驗下圖中圈出的欄位
在這裡插入圖片描述
在這裡插入圖片描述
一個使用WebSocket應用於視訊的業務思路如下:

  • 使用心跳維護websocket鏈路,探測客戶端端的網紅/主播是否線上
  • 設定負載均衡7層的proxy_read_timeout預設為60s
  • 設定心跳為50s,即可長期保持Websocket不斷開
    相關閱讀推薦

WebSocket長連線應用場景
搭建多終端《你畫我猜》Socket伺服器

相關文章