程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • WebSocket

    • WebSocket 基础篇
      • 一、为什么需要 WebSocket?
      • 二、WebSocket 简介
      • 三、WebSocket 客户端的简单示例
      • 四、WebSocket 客户端 API 详解
        • 4.1 WebSocket 构造函数
        • 4.2 WebSocket.readyState
        • 4.3 WebSocket.onopen
        • 4.4 WebSocket.onclose
        • 4.5 WebSocket.onmessage
        • 4.6 WebSocket.send()
        • 4.7 WebSocket.bufferedAmount
        • 4.8 WebSocket.onerror
      • 五、服务端的实现
        • 5.1 µWebSockets
        • 5.2 Socket.IO
        • 5.3 WebSocket-Node
        • 5.4 各实现的对比与总结
    • WebSocket 原理篇
    • J2EE WebSocket 实现方式
    • Spring WebSocket 实现方式
    • Spring WebSocket 高级实现方式
    • 在线聊天(单聊)案例
  • WebSocket
  • WebSocket
scholar
2024-09-18
目录

WebSocket 基础篇

# WebSocket 前端基础篇

# 一、为什么需要 WebSocket?

初次接触 WebSocket 的人,通常会问:我们已经有了 HTTP 协议,为什么还需要另一个协议?WebSocket 能带来什么好处?

答案很简单:因为 HTTP 协议的通信模式有局限性:通信只能由客户端发起。

举个例子,假设我们想要获取实时天气信息,通常的 HTTP 请求流程是由客户端(如浏览器)向服务器发起请求,服务器返回结果。HTTP 协议无法让服务器主动向客户端推送更新的信息。

HTTP通信方式

由于 HTTP 协议的单向请求特性,如果服务器的状态经常变化而客户端需要实时获取最新状态,这种情况就很麻烦。为了解决这个问题,通常采用轮询(Polling)的方式:客户端每隔一段时间就向服务器发送请求,询问是否有新信息。典型场景如聊天室。

然而,轮询效率低且资源浪费,因为它需要客户端不断地发起请求,或保持连接长时间打开。为了提高效率并解决这些问题,工程师们设计了 WebSocket。

# 二、WebSocket 简介

WebSocket 协议诞生于 2008 年,并在 2011 年成为国际标准。如今几乎所有主流浏览器都已支持。

WebSocket 最大的特点是:服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,实现真正的双向通信。 这使 WebSocket 成为一种重要的服务器推送技术。

WebSocket 双向通信

WebSocket 其他特点包括:

  1. 建立在 TCP 协议之上,服务器端实现相对简单。
  2. 与 HTTP 协议兼容性良好,使用相同的端口(80 和 443),握手阶段采用 HTTP 协议,使其容易通过防火墙和代理。
  3. 轻量的数据格式,减少传输开销,提高通信效率。
  4. 支持文本和二进制数据传输,灵活应对不同场景。
  5. 没有同源限制,允许客户端与任意服务器通信。
  6. 协议标识符为 ws(加密为 wss),服务器网址类似于 URL。
ws://example.com:80/some/path
1

WebSocket URL 格式

# 三、WebSocket 客户端的简单示例

WebSocket 的基本用法非常简单。以下是一个基础的 WebSocket 客户端脚本示例:

// 创建 WebSocket 连接
var ws = new WebSocket("wss://echo.websocket.org");

// 当连接成功时触发
ws.onopen = function(evt) {
    console.log("WebSocket 连接已打开...");
    // 连接成功后,向服务器发送消息
    ws.send("Hello WebSockets!");
};

// 当接收到服务器消息时触发
ws.onmessage = function(evt) {
    console.log("收到服务器消息: " + evt.data);
    // 在收到消息后关闭 WebSocket 连接
    ws.close();
};

// 当连接关闭时触发
ws.onclose = function(evt) {
    console.log("WebSocket 连接已关闭。");
};

// 当连接发生错误时触发
ws.onerror = function(evt) {
    console.error("WebSocket 连接发生错误: " + evt);
};
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

详细注释:

  1. var ws = new WebSocket("wss://echo.websocket.org");

    • 创建一个 WebSocket 对象并建立连接。wss:// 表示使用加密的 WebSocket 协议(类似 HTTPS)。
    • 连接地址为 wss://echo.websocket.org,这是一个用于测试的 WebSocket 服务器,它会将收到的消息原样返回。
  2. ws.onopen = function(evt) { ... }

    • 当 WebSocket 连接成功时,触发 onopen 事件。在这个事件中,可以执行连接后的初始化操作,如发送第一条消息。
  3. ws.send("Hello WebSockets!");

    • 使用 send 方法发送数据。这里发送了一条简单的文本消息。
  4. ws.onmessage = function(evt) { ... }

    • 当服务器发送消息时,触发 onmessage 事件。接收到的消息会包含在 evt.data 中。在本例中,收到消息后会打印到控制台,并立即关闭连接。
  5. ws.onclose = function(evt) { ... }

    • 当连接关闭时,触发 onclose 事件。通常用于清理资源或通知用户连接已结束。
  6. ws.onerror = function(evt) { ... }

    • 当连接出错时,触发 onerror 事件。这种情况下,可能需要处理错误或重试连接。

WebSocket 的常见应用场景

  1. 实时聊天应用:如微信、Slack 等。
  2. 实时通知系统:如股票价格推送、服务器监控报警等。
  3. 在线多人游戏:如多人协作游戏、对战游戏等。
  4. 实时数据分析与监控:如流媒体直播、运动数据分析等。

# 四、WebSocket 客户端 API 详解

在使用 WebSocket 时,了解客户端 API 的使用方法非常重要。以下是对常见 WebSocket 客户端 API 的详细总结,包括每个 API 的作用、使用方式,以及相关代码的详细注释。

# 4.1 WebSocket 构造函数

用法:通过 WebSocket 构造函数来新建一个 WebSocket 实例,建立客户端与服务器之间的连接。

// 创建一个 WebSocket 实例,指定要连接的服务器地址
var ws = new WebSocket('ws://localhost:8080');

// 当上面代码执行后,客户端将会与指定服务器进行连接
1
2
3
4

说明:WebSocket 构造函数接受一个 URL 参数,该参数指定要连接的服务器地址。ws:// 表示非加密连接,wss:// 表示加密连接。

# 4.2 WebSocket.readyState

用法:readyState 属性表示当前 WebSocket 连接的状态。

// 根据 WebSocket 的状态采取相应操作
switch (ws.readyState) {
  case WebSocket.CONNECTING:
    // 正在连接中
    console.log('WebSocket 正在连接...');
    break;
  case WebSocket.OPEN:
    // 连接已建立,可以通信
    console.log('WebSocket 连接已打开');
    break;
  case WebSocket.CLOSING:
    // 连接正在关闭
    console.log('WebSocket 正在关闭...');
    break;
  case WebSocket.CLOSED:
    // 连接已关闭或连接失败
    console.log('WebSocket 连接已关闭');
    break;
  default:
    // 不会发生,保留处理
    console.log('未知的 WebSocket 状态');
    break;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

状态值说明:

  • CONNECTING (0):正在建立连接。
  • OPEN (1):连接已建立,可以通信。
  • CLOSING (2):连接正在关闭。
  • CLOSED (3):连接已关闭或连接失败。

# 4.3 WebSocket.onopen

用法:onopen 事件用于在连接成功后触发回调函数。

// 监听 WebSocket 连接成功事件
ws.onopen = function () {
  console.log('WebSocket 连接成功');
  // 连接成功后向服务器发送消息
  ws.send('Hello Server!');
};

// 使用 addEventListener 添加多个回调函数
ws.addEventListener('open', function (event) {
  console.log('另一个连接成功的回调');
  ws.send('Another Hello Server!');
});
1
2
3
4
5
6
7
8
9
10
11
12

说明:onopen 是一个事件处理函数,当 WebSocket 连接成功时触发。可以使用 addEventListener 添加多个回调函数。

# 4.4 WebSocket.onclose

用法:onclose 事件用于在连接关闭后触发回调函数。

// 监听 WebSocket 连接关闭事件
ws.onclose = function (event) {
  // 获取关闭的状态码、原因和是否是干净关闭
  var code = event.code;
  var reason = event.reason;
  var wasClean = event.wasClean;

  console.log(`WebSocket 连接关闭,状态码: ${code}, 原因: ${reason}, 是否干净关闭: ${wasClean}`);
};

// 使用 addEventListener 监听关闭事件
ws.addEventListener('close', function (event) {
  console.log('WebSocket 已关闭: ', event);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14

说明:

  • event.code:关闭连接时的状态码。
  • event.reason:关闭连接的原因。
  • event.wasClean:是否为干净关闭,即没有数据丢失。

# 4.5 WebSocket.onmessage

用法:onmessage 事件用于在接收到服务器消息时触发回调函数。

// 监听 WebSocket 消息接收事件
ws.onmessage = function (event) {
  var data = event.data; // 获取收到的消息数据
  console.log('收到的消息: ', data);
};

// 使用 addEventListener 监听消息事件
ws.addEventListener('message', function (event) {
  console.log('收到的消息 (addEventListener): ', event.data);
});
1
2
3
4
5
6
7
8
9
10

说明:接收到的消息可以是文本数据或二进制数据(如 blob 或 ArrayBuffer)。可以通过 event.data 获取数据,并通过 binaryType 指定数据的格式。

// 动态判断数据类型
ws.onmessage = function(event){
  if(typeof event.data === 'string') {
    console.log("收到文本数据: " + event.data);
  } else if(event.data instanceof ArrayBuffer){
    console.log("收到二进制数据: ArrayBuffer");
  }
};

// 显式指定二进制数据类型为 blob
ws.binaryType = "blob";
ws.onmessage = function(e) {
  console.log("收到 Blob 数据大小: " + e.data.size);
};

// 显式指定二进制数据类型为 ArrayBuffer
ws.binaryType = "arraybuffer";
ws.onmessage = function(e) {
  console.log("收到 ArrayBuffer 数据长度: " + e.data.byteLength);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 4.6 WebSocket.send()

用法:send() 方法用于向服务器发送数据。

// 发送文本消息
ws.send('Hello Server!');

// 发送 Blob 对象
var file = document.querySelector('input[type="file"]').files[0];
ws.send(file);

// 发送 ArrayBuffer 数据
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
  binary[i] = img.data[i];
}
ws.send(binary.buffer);
1
2
3
4
5
6
7
8
9
10
11
12
13
14

说明:send() 方法支持发送多种数据类型,包括字符串、Blob、ArrayBuffer 等。发送二进制数据时,数据的处理方式取决于 binaryType 属性。

# 4.7 WebSocket.bufferedAmount

用法:bufferedAmount 属性表示还未发送的数据字节数。

// 发送大量数据并检查发送进度
var data = new ArrayBuffer(10000000); // 创建一个 10MB 的数据
ws.send(data);

if (ws.bufferedAmount === 0) {
  console.log("数据已全部发送");
} else {
  console.log("数据尚未发送完毕,剩余: " + ws.bufferedAmount + " 字节");
}
1
2
3
4
5
6
7
8
9

说明:当发送的数据量较大时,可以通过 bufferedAmount 检查是否有数据未完全发送。如果该值为 0,表示数据已发送完毕。

# 4.8 WebSocket.onerror

用法:onerror 事件用于在发生错误时触发回调函数。

// 监听 WebSocket 错误事件
ws.onerror = function(event) {
  console.error("WebSocket 发生错误: ", event);
};

// 使用 addEventListener 监听错误事件
ws.addEventListener('error', function(event) {
  console.error("WebSocket 错误 (addEventListener): ", event);
});
1
2
3
4
5
6
7
8
9

说明:当 WebSocket 连接发生错误时,会触发 onerror 事件。通常需要在此处理错误信息或进行日志记录。

# 五、服务端的实现

在构建 WebSocket 服务器时,可以选择不同的框架和库。以下是常见的几种 Node.js 实现以及它们的特点和基本用法总结。

# 5.1 µWebSockets

µWebSockets 是一款性能非常高的 WebSocket 库,特别适合高并发和低延迟的应用场景。它以其轻量和高效著称,能够处理数百万的 WebSocket 连接,常用于对性能要求极高的场景。

特点:

  • 极高的吞吐量,处理百万级别的连接。
  • 轻量化,内存占用低。
  • 高效的事件循环机制,适合实时性要求较高的应用。

安装与使用:

npm install uWebSockets.js
1

基本示例:

const uWS = require('uWebSockets.js');

// 创建一个 WebSocket 服务器
uWS.App().ws('/*', {
  // 连接建立时的回调
  open: (ws) => {
    console.log('客户端连接成功');
    ws.send('欢迎使用 µWebSockets!');
  },
  // 收到消息时的回调
  message: (ws, message, isBinary) => {
    const msg = Buffer.from(message).toString();
    console.log('收到消息:', msg);
    ws.send('服务端回复: ' + msg);
  },
  // 连接关闭时的回调
  close: (ws, code, message) => {
    console.log('客户端断开连接');
  }
}).listen(8080, (token) => {
  if (token) {
    console.log('WebSocket 服务器正在运行,端口: 8080');
  } else {
    console.log('服务器启动失败');
  }
});
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

# 5.2 Socket.IO

Socket.IO 是最为广泛使用的 WebSocket 库之一。它不仅支持 WebSocket,还兼容 HTTP 长轮询等多种通信协议,具有良好的兼容性和广泛的社区支持,适合需要兼容性和多功能性的应用。

特点:

  • 兼容性强,自动选择最佳的通信方式(WebSocket、轮询等)。
  • 支持房间、命名空间等功能,适合复杂的实时通信需求。
  • 拥有强大的生态系统,插件和中间件丰富。

安装与使用:

npm install socket.io
1

基本示例:

const io = require('socket.io')(3000);

// 监听客户端连接
io.on('connection', (socket) => {
  console.log('客户端连接成功');

  // 监听消息
  socket.on('message', (msg) => {
    console.log('收到消息:', msg);
    socket.emit('response', '服务端回复: ' + msg);
  });

  // 监听断开连接
  socket.on('disconnect', () => {
    console.log('客户端断开连接');
  });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 5.3 WebSocket-Node

WebSocket-Node 是一个较为简单且符合 WebSocket 标准的实现,适合需要直接操作 WebSocket 协议的场景。它提供了对标准 WebSocket 协议的完整支持,适合开发者根据需要进行高度定制。

特点:

  • 符合 WebSocket 标准,灵活性高。
  • 轻量且简单,适合进行自定义实现。
  • 社区活跃度较高,文档详细。

安装与使用:

npm install websocket
1

基本示例:

const WebSocketServer = require('websocket').server;
const http = require('http');

// 创建 HTTP 服务器
const server = http.createServer((req, res) => {
  res.writeHead(404);
  res.end();
});

server.listen(8080, () => {
  console.log('WebSocket 服务器正在运行,端口: 8080');
});

// 绑定 WebSocket 服务器到 HTTP 服务器
const wsServer = new WebSocketServer({
  httpServer: server
});

// 监听 WebSocket 请求
wsServer.on('request', (request) => {
  const connection = request.accept(null, request.origin);
  console.log('客户端连接成功');

  // 监听消息
  connection.on('message', (message) => {
    if (message.type === 'utf8') {
      console.log('收到消息:', message.utf8Data);
      connection.sendUTF('服务端回复: ' + message.utf8Data);
    }
  });

  // 监听断开连接
  connection.on('close', (reasonCode, description) => {
    console.log('客户端断开连接');
  });
});
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
28
29
30
31
32
33
34
35
36

# 5.4 各实现的对比与总结

库名称 性能 兼容性 功能丰富度 社区支持 适用场景
µWebSockets 极高 中等 基础 一般 高性能、高并发的实时应用
Socket.IO 中高 极高 丰富 极高 需要兼容性、复杂通信需求的应用
WebSocket-Node 中等 标准 WebSocket 基础 一般 简单的 WebSocket 应用,需高度自定义的场景

总结:选择适合的 WebSocket 实现取决于项目的需求。如果你需要兼容性和丰富的功能,Socket.IO 是首选;如果你追求极致性能,µWebSockets 是更好的选择;而 WebSocket-Node 则适合对协议和功能有精细控制的场景。

编辑此页 (opens new window)
上次更新: 2024/12/28, 18:32:08
WebSocket 原理篇

WebSocket 原理篇→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式