阿Han
阿Han

文字是留下記錄的一種媒介,將知識吸收轉化後輸出成文字進行保存。 ☕️ https://liker.land/willhanchen/civic

【Web微知識系列】雙向溝通的技術,什麼是Websocket?

進入本篇章前建議您可以先了解以下兩個篇章,主要是介紹單向過程中的訂閱概念:

這種雙向溝通機制主要是為了更即時的反應,舉例來說今天我們有一個應用是即時語音辨識,那麼勢必會有一個互動的過程,使用者端進行錄音後,即時的送到伺服器進行辨識並將辨識結果即時呈現於畫面上時,就必須透過這種雙向溝通機制才能完成。

簡介

傳統的Http是一種Stateless的傳輸方式, 因此不會維持原本狀態, 而是需要更新、新增、查詢...等操作時才進行請求, 因此假設有即時性互動的應用時就不太適用了, 因為每進行一個動作就要向Server端發送請求, 而每次的請求都必須經過交握式連接的過程, 在效能上就不是那麼理想了, Websocket允許瀏覽器跟Server端只經過一次的交握過程, 就能建立一條長連接的溝通管道, 並透過這條管道進行「雙向傳輸」。

Websocket與TCP、HTTP的關係

  • Websocket與HTTP屬於應用層, 同樣都是基於TCP來進行傳輸, 而進行Handshake時也會透過HTTP進行, 但真正傳輸資料時就不必經過HTTP的方式。

圖片來源

  • 與HTTP一樣可以進行加密傳輸, HTTP的部份為https, Websocket則為wss

圖片來源

為什麼要使用Websocket?

其實以往我們網頁資料刷新有以下幾種方式可以實作:

Polling

這種方式是早期透過Javascript定時(setIntervalsetTimeout)來向後端請求最新資料並呈現於頁面之上, 這麼做的好處是容易實現, 但我們並不知曉Server端何時會更新, 只能傻傻的定時獲取, 造成的影響就是頻寬的浪費以及資料呈現不即時。

圖片來源

Long-Polling

長時間輪詢的方式就是收到前端請求後, Server端會等待, 若這段時間有資料就會將最新資料回傳給前端, 因此等待的這段期間Client什麼事情也不用做, 等待資料回傳後再發送下一個請求, 雖然長時間的連接解決了Polling開銷的問題, 但如果在更新資料很頻繁的狀況下也會造成連續的Polling的動作產生, 未必效能較佳。

圖片來源

Server Sent Events

這種方式比較少被使用, 因為SSE能做的功能Websocket也能完成, 差別只是雙向溝通還是單向溝通而已, 不過在某些應用上, 瀏覽器不太需要傳遞資料給Server端, 例如: 股市行情、即時新聞...等, 只需要接收Server端的最新資料即可, 不太需要主動發送, 當然實作起來也較容易, 簡單來說就是伺服端單向的推送資料給瀏覽器。

圖片來源

Websocket

以上幾個方式的共同點就是都基於HTTP進行傳輸, 而我們也知道HTTP的傳輸為了確保正確性會帶有較多的標頭...等資訊, 而Websocket只有一開始確定連線時會走HTTP以外, 之後的傳輸都不是基於HTTP, 因此傳輸上會來的更有效率, 且提供了雙向溝通的功能。

圖片來源

常見的線上互動遊戲、雲端協作、線上聊天...等, 若使用上述的幾種方式都有延遲的議題存在,因此需要即時互動的應用就非常適合使用Websocket的方式來進行實作。

建立連接

  • 以javascript來說, 通常我們在建立Websocket物件的時候, Browser就開始進行Handshake的過程。
var socket = new WebSocket("ws://127.0.0.1:8080/ws")
  • 建立連線成功後,會發送支援的版本號、主機地址...等資訊給Server端。
Accept-Encoding: gzip, deflate

Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7

Cache-Control: no-cache

Connection: Upgrade

Host: 127.0.0.1:8080

Origin: http:*//127.0.0.1:8080*

Pragma: no-cache

Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

Sec-WebSocket-Key: sZrnswRjM0ZXxxmAIJhrvQ==

Sec-WebSocket-Version: 13

Upgrade: websocket

User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36
  • Server端收到後會回傳狀態碼101及相關資訊。
HTTP/1.1 101 Switching Protocols

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Accept: 3zg/SIKvYpT51lJJKbF4WjFuCTY=

Access-Control-Allow-Origin: *

Access-Control-Allow-Headers: Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization
  • 如果過程失敗的話就會進入onerror的handler, 成功的話就代表可以開始傳輸資料。

如何確保連線狀態

假設連線的過程中發生了以下兩種狀況:

  1. 長時間不發送訊息或者防火牆阻擋了連接, Server端無法得知。
  2. Client端與Server端之間斷開網路, Server端也未感知。

此時就需要一種Heartbeat的機制, 來偵測彼此的連線是否存活。

  1. 由發送端發送ping訊號給接收端。
  2. 接收端成功收到之後, 回應pong訊號給發送端。
  3. 成功接收到pong訊號, 代表連線正常。
發送端 -> ping -> 接收端

發送端 <- pong <- 接收端

對於Client端來說就有開發者提供了Heartbeat的套件websocket-heartbeat-js, 讓我們開發前端時省去自行實做的時間。

📝 Web微知識系列文章


喜歡撰寫文章的你,不妨來了解一下:

Web3.0時代下為創作者、閱讀者打造的專屬共贏平台 - 為什麼要加入?

歡迎加入一起練習寫作,賺取知識,累積財富!

CC BY-NC-ND 2.0 版权声明

喜欢我的文章吗?
别忘了给点支持与赞赏,让我知道创作的路上有你陪伴。

加载中…
加载中…

发布评论