WebSocket 的原理以及如何使用
前言
WebSocket 是 HTML5 引入的一项重要特性,它允许在浏览器和服务器之间建立双向通信。
与 HTTP 请求-响应模式不同,WebSocket 允许在一个连接上进行持续的双向数据传输,而不需要频繁地建立和关闭连接。这使得 WebSocket 适用于实时性要求较高的应用,如聊天应用、实时广播、股票市场等。
WebSocket 协议标识是 ws
(未加密)和 wss
(加密),类似于 HTTP 的 http
和 https
。
const socket = new WebSocket("ws://example.com/socket")
WebSocket 的特点
双向通信
WebSocket 允许在同一个连接上同时发送和接收数据,从而实现实时双向通信。
持久连接
一旦建立了 WebSocket 连接,它会保持打开状态,直到显式关闭连接。
低延迟
WebSocket 的双向通信性质使得数据传输更加即时,相比传统的 HTTP 请求,减少了通信延迟。
轻量级
与 HTTP 相比,WebSocket 协议头较小,减少了数据传输时的开销。
支持跨域
WebSocket 允许在不同域名之间进行通信,通过协议和安全措施确保通信安全性。
WebSocket 工作原理
-
握手阶段: 客户端发起一个 HTTP 请求到服务器,请求升级为 WebSocket 连接。服务器验证请求后,将连接升级为 WebSocket。
-
双向通信: 一旦 WebSocket 连接建立,客户端和服务器可以在任何时候互相发送数据。数据可以以帧的形式传输,每个帧可以是文本或二进制数据。
-
关闭连接: 任一方可以在任何时候关闭 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 心跳机制的基本原理:
-
定时发送心跳包: 客户端和服务器都会定期发送心跳包,通常是一个空的或含有很少数据的消息,例如一个单字节的数据。这些心跳包的目的是告诉对方连接仍然活跃。
-
监测响应: 一旦一方发送了心跳包,另一方会回复一个响应(称为 pong),以表示连接正常。
-
检测连接状态: 如果一方在预定的时间内未收到心跳包或响应,就可以推断连接可能出现问题。在这种情况下,可以采取措施来重新建立连接或处理连接断开的情况。
示例代码:
<!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 协议。在需要双向通信的应用场景下非常有用,实时性非常高且不受跨域限制。