Skip to content

WebSocket

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,与 HTTP 不同,它允许服务器主动向客户端推送数据

建立连接过程

客户端发起 HTTP 握手请求(HTTP Upgrade)

客户端通过发送一个特殊的 HTTP 请求来“升级”到 WebSocket 协议

GET /chat HTTP/1.1
Host: example.com:80
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
  • Upgrade: websocket:请求升级协议为 WebSocket
  • Connection: Upgrade:表明这是一个升级请求
  • Sec-WebSocket-Key:客户端生成的随机 Base 64 编码字符串,供服务器验证
  • Sec-WebSocket-Version:指定 WebSocket 协议版本(当前为 13)

服务器响应握手

服务器如果同意升级,就返回如下响应:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
  • 101 Switching Protocols:状态码表示协议切换完成,之后使用 WebSocket 进行通信

建立连接后通信

握手成功后,HTTP 协议升级为 WebSocket 协议,之后通信不再使用 HTTP,而是使用 WebSocket 帧(frame)进行双向传输

客户端和服务器可以随时相互发送消息,保持连接直到任一方关闭

代码实现

使用 Node.Js 来搭建一个简单的 WebSocket 服务

服务端

js
const Websocker = require('ws');

// 创建一个 WebSocket 服务器,指定端口为 8080
const wss = new Websocker.Server({ port: 8080 });

// 监听连接事件
wss.on('connection', (ws) => {

    console.log('客户端已连接');
    ws.on('message', (message) => {
        console.log(`收到消息: ${message}`);
        // 发送数据
        ws.send(`${message},欢迎连接到 WebSocket 服务器!`);
    });

    // 监听关闭事件,在一个 Connection 内
    ws.on('close', () => {
        console.log('客户端已断开连接');
    });
});

客户端

js
const ws= require('ws');

// 创建一个 WebSocket 客户端,连接到指定的服务器地址
const wsClient = new ws('ws://localhost:8080');

// 监听连接事件
wsClient.on('open', () => {
    console.log('已连接到服务器');
    // 发送数据
    wsClient.send('Hello, server!');
});
wsClient.on('message', (message) => {
    console.log(`收到来自服务器的消息: ${message}`);
});

我觉得用 Node.Js 当客户端调试有点麻烦,这里使用 ApiFox:

广播通信

WebSocket 是一对一的:客户端连接到服务器,服务器再与客户端通信,要实现多个客户端之间的通信(如聊天室),需要通过服务器进行转发或广播

  1. 所有客户端连接到 WebSocket 服务器
  2. 某个客户端发送消息到服务器
  3. 服务器接收后,将消息转发给所有其他客户端,或广播给所有客户端(包括自己)
js
// server.js
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws) {
    console.log('新客户端已连接');

    ws.on('message', function incoming(message) {
        console.log('收到消息:', message.toString());

        // 广播给所有客户端
        wss.clients.forEach(function each(client) {
            if (client.readyState === WebSocket.OPEN) {
                // 转发全部信息到全部客户端
                client.send(message.toString());
            }
        });
    });
    ws.send('欢迎加入聊天室!');
    const onlineCount = wss.clients.size;
    ws.send(`当前在线用户数量: ${onlineCount}`);
});

当然连接是有先后顺序的,并不会存储用户信息

多群组的设计

设计的关键在于:

  1. 给每个客户端分配一个“群组”标识(如房间名)
  2. 服务器记录每个群组有哪些客户端
  3. 只在特定群组中广播消息

最后更新于:

Released under the MIT License.