WebSocket 的原理以及如何使用

前言

WebSocket 是 HTML5 引入的一項重要特性,它允許在瀏覽器和服務器之間建立雙向通信。

與 HTTP 請求-響應模式不同,WebSocket 允許在一個連接上進行持續的雙向數據傳輸,而不需要頻繁地建立和關閉連接。這使得 WebSocket 適用于實時性要求較高的應用,如聊天應用、實時廣播、股票市場等。

WebSocket 協議標識是 ws(未加密)和 wss(加密),類似于 HTTP 的 httphttps

const socket = new WebSocket("ws://example.com/socket")

WebSocket 的特點

雙向通信

WebSocket 允許在同一個連接上同時發送和接收數據,從而實現實時雙向通信。

持久連接

一旦建立了 WebSocket 連接,它會保持打開狀態,直到顯式關閉連接。

低延遲

WebSocket 的雙向通信性質使得數據傳輸更加即時,相比傳統的 HTTP 請求,減少了通信延遲。

輕量級

與 HTTP 相比,WebSocket 協議頭較小,減少了數據傳輸時的開銷。

支持跨域

WebSocket 允許在不同域名之間進行通信,通過協議和安全措施確保通信安全性。

WebSocket 工作原理

  1. 握手階段: 客戶端發起一個 HTTP 請求到服務器,請求升級為 WebSocket 連接。服務器驗證請求后,將連接升級為 WebSocket。

  2. 雙向通信: 一旦 WebSocket 連接建立,客戶端和服務器可以在任何時候互相發送數據。數據可以以幀的形式傳輸,每個幀可以是文本或二進制數據。

  3. 關閉連接: 任一方可以在任何時候關閉 WebSocket 連接,觸發關閉握手。

WebSocket 的屬性

readyState

WebSocket 有多個屬性,其中 readyState 是最常用的,用來表示連接狀態,它定義以下幾個常量用來表示:

常量 說明
WebSocket.CONNECTING 0 表示正在連接中。
WebSocket.OPEN 1 表示連接已建立,可以進行通信。
WebSocket.CLOSING 2 表示連接正在關閉。
WebSocket.CLOSED 3 表示連接已經關閉或者連接未成功。

示例代碼:

console.log(WebSocket.CONNECTING) // 0
console.log(WebSocket.OPEN) // 1
console.log(WebSocket.CLOSING) // 2
console.log(WebSocket.CLOSED) // 3

const socket = new WebSocket("ws://example.com/socket")

socket.onopen = event => {
  console.log(socket.readyState) // 1
}

當然除了 readyState 還有一些別的屬性,但不常用,這里不做過多介紹。如果需要請參考:WebSocket - Web API 接口參考 | MDN

WebSocket 的四個事件

open

連接建立時觸發

const socket = new WebSocket("ws://example.com/socket")

// 當連接建立時
socket.onopen = event => {
  console.log("WebSocket connection established.")
}

// 或者
socket.addEventListener("open", function (event) {
  console.log("WebSocket connection established.")
})

message

客戶端接收服務端數據時觸發

const socket = new WebSocket("ws://example.com/socket")

// 當收到消息時
socket.onmessage = event => {
  console.log("Message from server ", event.data)
}

// 或者
socket.addEventListener("message", function (event) {
  console.log("Message from server ", event.data)
})

error

通信發生錯誤時觸發

const socket = new WebSocket("ws://example.com/socket")

socket.onerror = error => {
  console.error("WebSocket error: " + error)
}

close

連接關閉時觸發

const socket = new WebSocket("ws://example.com/socket")
socket.onclose = event => {
  console.log("WebSocket connection closed: " + event.code + " " + event.reason)
}

WebSocket 的兩個方法

Socket.send()

使用連接發送數據

// 創建 WebSocket 連接
const socket = new WebSocket("ws://example.com/socket")

socket.send("Client Message")

Socket.close()

關閉連接

// 創建 WebSocket 連接
const socket = new WebSocket("ws://example.com/socket")

// 關閉 WebSocket 連接
socket.close()

// 關閉 WebSocket 連接并指定狀態碼和原因
socket.close(1000, "Connection closed by user")

前端完整使用示例

<!DOCTYPE html>
<html>
  <head>
    <title>WebSocket Example</title>
  </head>
  <body>
    <h1>WebSocket Example</h1>
    <div id="messages"></div>

    <script>
      // 創建 WebSocket 連接
      const socket = new WebSocket("ws://example.com/socket")

      // 當連接建立時
      socket.onopen = event => {
        console.log("WebSocket connection established.")
      }

      // 當收到消息時
      socket.onmessage = event => {
        console.log("Message from server ", event.data)
      }

      // 當連接關閉時
      socket.onclose = event => {
        console.log("WebSocket connection closed: " + event.code + " " + event.reason)
      }

      // 當發生錯誤時
      socket.onerror = error => {
        console.error("WebSocket error: " + error)
      }

      // 發送消息
      function sendMessage() {
        const message = prompt("Enter a message:")
        if (message) {
          socket.send(message)
        }
      }

      // 關閉 WebSocket 連接
      socket.close()

      // 關閉 WebSocket 連接并指定狀態碼和原因
      socket.close(1000, "Connection closed by user")
    </script>
  </body>
</html>

WebSocket 的心跳機制

心跳機制是一種民間說法,不是必須的,目的是為了保持 WebSocket 連接,防止連接意外斷開的一種機制。一般通過定期發送小型數據包(稱為心跳包或 ping)來維持 WebSocket 連接,以確保連接不會因為長時間沒有數據傳輸而被關閉。

以下是 WebSocket 心跳機制的基本原理:

  1. 定時發送心跳包: 客戶端和服務器都會定期發送心跳包,通常是一個空的或含有很少數據的消息,例如一個單字節的數據。這些心跳包的目的是告訴對方連接仍然活躍。

  2. 監測響應: 一旦一方發送了心跳包,另一方會回復一個響應(稱為 pong),以表示連接正常。

  3. 檢測連接狀態: 如果一方在預定的時間內未收到心跳包或響應,就可以推斷連接可能出現問題。在這種情況下,可以采取措施來重新建立連接或處理連接斷開的情況。

示例代碼:

<!DOCTYPE html>
<html>
  <head>
    <title>WebSocket Heartbeat Example</title>
  </head>
  <body>
    <h1>WebSocket Heartbeat Example</h1>

    <script>
      const ws = new WebSocket("wss://example.com/socket") // 替換為實際的WebSocket地址

      // 心跳間隔(毫秒)
      const heartbeatInterval = 5000 // 每5秒發送一次心跳包

      // 定時發送心跳包
      const heartbeat = () => {
        if (ws.readyState === WebSocket.OPEN) {
          console.log("Sending heartbeat")
          ws.send("heartbeat")
        }
      }

      ws.addEventListener("open", event => {
        console.log("WebSocket connection established.")

        // 開始定時發送心跳包
        setInterval(heartbeat, heartbeatInterval)
      })

      ws.addEventListener("message", event => {
        if (event.data === "pong") {
          console.log("Received pong response.")
        } else {
          console.log("Received message:", event.data)
        }
      })

      ws.addEventListener("close", event => {
        console.log("WebSocket connection closed:", event.code, event.reason)
      })

      ws.addEventListener("error", error => {
        console.error("WebSocket error:", error)
      })
    </script>
  </body>
</html>

WebSocket 和 HTTP/2 有什么異同點

WebSocket 和 HTTP/2 都支持 雙向通信,但有所區別。

用途

  • WebSocket:主要用于實現實時、持續的雙向通信,比如聊天應用、游戲等場景。
  • HTTP/2:主要用于優化單向請求-響應模式下的數據傳輸,特別是在加載網頁資源時提高性能。

通信模式

  • WebSocket:通信模式是全雙工(Full-duplex),允許客戶端和服務器在同一連接上同時發送和接收數據。
  • HTTP/2:通信模式是半雙工(Half-duplex),雖然支持服務器推送,但仍然需要在請求和響應之間切換。

連接維持

  • WebSocket:連接建立后保持持久連接,適用于實時通信。
  • HTTP/2:復用單一連接,減少了建立連接的開銷,但不像 WebSocket 那樣持久。

總結

WebSocket 使用 HTTP 協議進行連接,然后升級為 WebSocket 協議。在需要雙向通信的應用場景下非常有用,實時性非常高且不受跨域限制。


參考文檔

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,310評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,951評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,566評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,055評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,303評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,799評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,683評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,899評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,135評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,528評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,844評論 2 372

推薦閱讀更多精彩內容