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阅读 200,527评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,314评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,535评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,006评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,961评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,220评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,664评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,351评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,481评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,397评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,443评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,123评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,713评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,801评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,010评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,494评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,075评论 2 341

推荐阅读更多精彩内容