15 WebSocket
loyalvi Lv7

12 WebSocket

WebSocket

WebSocket 是一种网络通信协议,它提供了一种在单个 TCP 连接上进行全双工通信的方式。WebSocket 允许服务器主动向客户端发送数据,而不需要客户端不断发送请求来轮询服务器。这种特性使得 WebSocket 非常适合需要实时数据传输的应用,如在线聊天、实时游戏、股票行情更新等。

WebSocket 的特点

  • 全双工通信:WebSocket 连接允许服务器和客户端之间同时进行数据的发送和接收,而不需要像 HTTP 请求那样等待对方的响应。
  • 持久连接:一旦 WebSocket 连接建立,它会保持打开状态,直到客户端或服务器显式地关闭连接。这避免了频繁地建立和关闭连接的开销。
  • 基于 HTTP 的握手:WebSocket 连接的建立是通过 HTTP 请求完成的,称为 WebSocket 握手。服务器在接收到 WebSocket 握手请求后,会将连接升级为 WebSocket 连接。
  • 二进制数据传输:WebSocket 支持传输二进制数据,如 Blob 或 ArrayBuffer,这使得 WebSocket 能够高效地传输图像、音频、视频等二进制文件。

WebSocket 的工作流程

  1. 握手:客户端通过发送一个特殊的 HTTP 请求来请求 WebSocket 连接。这个请求包含一个 Upgrade 头,表明客户端希望将连接升级为 WebSocket 连接。服务器如果同意升级,则会返回一个响应,将连接升级为 WebSocket 连接。
  2. 数据传输:一旦 WebSocket 连接建立,客户端和服务器就可以通过该连接自由地发送和接收数据。数据可以是文本数据,也可以是二进制数据。
  3. 关闭连接:WebSocket 连接可以由客户端或服务器关闭。关闭连接时,需要发送一个关闭帧,对方收到后也会关闭连接。

WebSocket API

在 JavaScript 中,可以通过 WebSocket 对象来使用 WebSocket 协议。以下是一些常用的属性和方法:

  • 属性
    • readyState:表示 WebSocket 连接的状态。可能的值有:
      • 0:连接尚未建立(CONNECTING)
      • 1:连接已建立(OPEN)
      • 2:正在关闭连接(CLOSING)
      • 3:连接已关闭(CLOSED)
    • bufferedAmount:表示已发送但尚未被浏览器传输的数据量(以字节为单位)。
    • extensions:表示服务器选择的 WebSocket 扩展。
    • protocol:表示服务器选择的子协议。
    • url:表示 WebSocket 连接的 URL。
  • 方法
    • constructor(url, [protocols]):创建一个新的 WebSocket 对象。url 是 WebSocket 服务器的地址,protocols 是可选的,可以指定一个或多个子协议。
    • send(data):向服务器发送数据。data 可以是字符串、Blob 或 ArrayBuffer。
    • close([code], [reason]):关闭 WebSocket 连接。code 是关闭连接的状态码,reason 是关闭连接的原因。
  • 事件
    • open:当 WebSocket 连接成功建立时触发。
    • error:当 WebSocket 连接发生错误时触发。
    • message:当从服务器接收到数据时触发。
    • close:当 WebSocket 连接关闭时触发。

示例代码

以下是一个简单的 WebSocket 客户端示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 创建WebSocket连接
const socket = new WebSocket('wss://example.com/socket');
// 连接成功时的处理
socket.addEventListener('open', function(event) {
console.log('WebSocket连接已建立');
socket.send('Hello, Server!'); // 向服务器发送数据
});
// 接收到服务器数据时的处理
socket.addEventListener('message', function(event) {
console.log('收到服务器数据:', event.data);
});
// 连接关闭时的处理
socket.addEventListener('close', function(event) {
console.log('WebSocket连接已关闭');
});
// 发生错误时的处理
socket.addEventListener('error', function(event) {
console.error('WebSocket连接发生错误');
});

WebSocket 协议的出现极大地简化了实时通信的开发,使得开发者可以更方便地实现各种实时交互功能。

WebSocket心跳机制

WebSocket心跳机制是用于维持客户端与服务器之间长连接的一种保活机制,通过定时发送心跳包来保持连接的活跃状态,防止因长时间无通讯而导致的自动断开。以下是心跳机制的详细说明:

一、心跳机制的实现方式

  1. 客户端定时向服务器发送心跳数据包
    • 客户端每隔一定时间(通常小于60秒)向服务器发送一个心跳数据包,服务器收到后返回一个响应。这种方式可以保持连接的活跃状态,防止连接因长时间无活动而被关闭。
    • 示例代码:
      1
      2
      3
      this.heartbeatTimer = setInterval(() => {
      ws.send('{"event":"ping","content":"ping heartbeat"}');
      }, originData.ping_interval); // originData.ping_interval 是心跳间隔时间
  2. 服务器定时向客户端发送心跳数据包
    • 服务器每隔一定时间向客户端发送一个心跳数据包,客户端收到后返回一个响应。这种方式可以检测客户端连接是否正常。
    • 示例代码(服务端配置):
      1
      2
      3
      4
      $gateway = new Gateway("websocket://0.0.0.0:8783");
      $gateway->pingInterval = 55; // 心跳检测时间间隔,单位:秒
      $gateway->pingNotResponseLimit = 0; // 客户端连续多少次不响应心跳时关闭连接
      $gateway->pingData = '{"type":"ping"}'; // 服务端发送的心跳数据
  3. 双向发送心跳数据包
    • 客户端和服务器都定时发送心跳数据包,这种方式可以更全面地检测连接状态。

二、心跳机制的原理

  1. 客户端建立WebSocket连接
    • 客户端通过new WebSocket(url)建立连接。
  2. 客户端向服务器发送心跳数据包
    • 客户端定时发送心跳数据包,服务器接收并返回响应。
  3. 服务器没有及时接收到心跳数据包
    • 如果服务器在设定时间内没有收到客户端的心跳数据包,会发送一个关闭连接的请求。
  4. 服务器定时向客户端发送心跳数据包
    • 服务器定时发送心跳数据包,客户端接收并返回响应。
  5. 客户端没有及时接收到心跳数据包
    • 如果客户端在设定时间内没有收到服务器的心跳数据包,会重新连接WebSocket。

三、心跳机制的作用

  1. 保持WebSocket连接不被断开
    • 通过定时发送心跳数据包,可以防止连接因长时间无活动而被关闭。
  2. 检测WebSocket连接状态
    • 可以及时发现连接是否异常断开,从而进行重连等操作。
  3. 减少资源消耗
    • 通过心跳机制,可以减少因连接异常断开而重新建立连接的次数,从而减少资源消耗。

四、心跳机制的必要性

WebSocket心跳机制是必要的,它可以使WebSocket连接保持长连接,避免断开连接的情况发生。同时,心跳机制也可以检查WebSocket连接的状态,及时处理异常情况。

五、心跳机制的实现示例

客户端实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
let ws = new WebSocket("ws://127.0.0.1:8783");
ws.onopen = function(evt) {
console.log('连接成功');
startHeartBeat(30000); // 每30秒发送一次心跳
};
ws.onmessage = function(evt) {
console.log('收到消息: ' + evt.data);
// 重置心跳超时
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
console.log('心跳无响应,已断线');
ws.close();
// 重连操作
}, 30000);
};
ws.onclose = function(evt) {
console.log('连接关闭');
// 重连操作
setTimeout(() => {
ws = new WebSocket("ws://127.0.0.1:8783");
}, 1000);
};
function startHeartBeat(interval) {
this.heartbeatTimer = setInterval(() => {
ws.send('{"event":"ping","content":"ping heartbeat"}');
}, interval);
}

服务端实现(以Node.js为例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8783 });
wss.on('connection', function connection(ws) {
console.log('客户端连接成功');
ws.on('message', function incoming(message) {
console.log('收到消息: %s', message);
if (message.includes('ping')) {
ws.send('{"event":"pong","content":"pong heartbeat"}');
}
});
// 服务端定时发送心跳数据包
setInterval(() => {
ws.send('{"type":"ping"}');
}, 55000); // 每55秒发送一次心跳
});

通过以上实现,可以有效地保持WebSocket连接的活跃状态,及时发现并处理连接异常。

由 Hexo 驱动 & 主题 Keep
访客数 访问量