WebSocket实时通信入门,感谢我的好搭档脉脉

🎁个人主页:User_芊芊君子

🎉欢迎大家点赞👍评论📝收藏⭐文章

🔍系列专栏:AI


文章目录:

WebSocket实时通信:从零开始的实用指南

为什么你的网页需要刷新才能看到新消息?为什么在线游戏有延迟?答案都在WebSocket技术里。


一、什么是WebSocket?

1.1 传统HTTP的问题

想象你在等快递:

复制代码
传统HTTP:你每隔10分钟打个电话问"到了吗?"(轮询)
WebSocket:快递到了主动给你打电话(推送)

传统HTTP通信的局限:
服务器 客户端 服务器 客户端 传统HTTP模式 等待... 大量无效请求 发起请求 返回数据 再次请求 返回数据

1.2 WebSocket的优势

WebSocket是全双工通信,意味着:

特性 HTTP WebSocket
连接方式 每次请求新建连接 一次连接,持续通信
数据流向 客户端主动请求 双向随时推送
实时性 有延迟(轮询间隔) 毫秒级实时
服务器资源 消耗大(频繁连接) 消耗小(长连接)

WebSocket通信流程:
服务器 客户端 服务器 客户端 WebSocket握手 保持连接,双向通信 HTTP升级请求 升级确认 发送消息 推送消息 发送消息 推送消息


二、快速上手:5分钟实现WebSocket

2.1 前端实现(原生JavaScript)

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>WebSocket聊天示例</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 600px;
            margin: 50px auto;
            padding: 20px;
        }
        #messages {
            height: 300px;
            border: 1px solid #ddd;
            overflow-y: auto;
            padding: 10px;
            margin-bottom: 10px;
            background: #f9f9f9;
        }
        .message {
            margin: 5px 0;
            padding: 8px;
            background: white;
            border-radius: 5px;
        }
        .sent {
            background: #e3f2fd;
        }
        .received {
            background: #f1f8e9;
        }
        #input-area {
            display: flex;
            gap: 10px;
        }
        input {
            flex: 1;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
        button {
            padding: 10px 20px;
            background: #2196F3;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }
        button:hover {
            background: #1976D2;
        }
        #status {
            margin-bottom: 10px;
            padding: 10px;
            border-radius: 5px;
            text-align: center;
        }
        .connected {
            background: #c8e6c9;
            color: #2e7d32;
        }
        .disconnected {
            background: #ffcdd2;
            color: #c62828;
        }
    </style>
</head>
<body>
    <h1>🔄 WebSocket实时聊天</h1>

    <div id="status" class="disconnected">⚫ 未连接</div>

    <div id="messages"></div>

    <div id="input-area">
        <input type="text" id="messageInput" placeholder="输入消息..." />
        <button onclick="sendMessage()">发送</button>
    </div>

    <script>
        // WebSocket连接
        const ws = new WebSocket('ws://localhost:8080');

        // DOM元素
        const statusDiv = document.getElementById('status');
        const messagesDiv = document.getElementById('messages');
        const input = document.getElementById('messageInput');

        // 连接成功
        ws.onopen = function() {
            statusDiv.textContent = '🟢 已连接';
            statusDiv.className = 'connected';
            addMessage('系统', '已连接到服务器', 'received');
        };

        // 接收消息
        ws.onmessage = function(event) {
            const data = JSON.parse(event.data);
            addMessage(data.user, data.message, 'received');
        };

        // 连接关闭
        ws.onclose = function() {
            statusDiv.textContent = '⚫ 连接断开';
            statusDiv.className = 'disconnected';
            addMessage('系统', '连接已断开', 'received');
        };

        // 连接错误
        ws.onerror = function(error) {
            console.error('WebSocket错误:', error);
        };

        // 发送消息
        function sendMessage() {
            const message = input.value.trim();
            if (message && ws.readyState === WebSocket.OPEN) {
                const data = {
                    user: '我',
                    message: message,
                    timestamp: new Date().toISOString()
                };
                ws.send(JSON.stringify(data));
                addMessage('我', message, 'sent');
                input.value = '';
            }
        }

        // 添加消息到界面
        function addMessage(user, message, type) {
            const div = document.createElement('div');
            div.className = `message ${type}`;
            const time = new Date().toLocaleTimeString();
            div.textContent = `[${time}] ${user}: ${message}`;
            messagesDiv.appendChild(div);
            messagesDiv.scrollTop = messagesDiv.scrollHeight;
        }

        // 回车发送
        input.addEventListener('keypress', function(e) {
            if (e.key === 'Enter') {
                sendMessage();
            }
        });
    </script>
</body>
</html>

2.2 后端实现(Node.js)

javascript 复制代码
// 安装依赖: npm install ws
const WebSocket = require('ws');

// 创建WebSocket服务器
const wss = new WebSocket.Server({ port: 8080 });

// 存储所有连接的客户端
const clients = new Set();

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

    // 添加到客户端集合
    clients.add(ws);

    // 欢迎消息
    ws.send(JSON.stringify({
        user: '系统',
        message: '欢迎加入聊天室!',
        timestamp: new Date().toISOString()
    }));

    // 接收消息
    ws.on('message', function(message) {
        const data = JSON.parse(message);

        console.log(`收到消息: ${data.message}`);

        // 广播给所有客户端
        clients.forEach(client => {
            if (client.readyState === WebSocket.OPEN) {
                client.send(JSON.stringify(data));
            }
        });
    });

    // 连接关闭
    ws.on('close', function() {
        console.log('客户端断开连接');
        clients.delete(ws);

        // 通知其他客户端
        broadcast({
            user: '系统',
            message: '有人离开了聊天室',
            timestamp: new Date().toISOString()
        });
    });

    // 错误处理
    ws.on('error', function(error) {
        console.error('WebSocket错误:', error);
    });
});

// 广播函数
function broadcast(data) {
    clients.forEach(client => {
        if (client.readyState === WebSocket.OPEN) {
            client.send(JSON.stringify(data));
        }
    });
}

console.log('WebSocket服务器运行在 ws://localhost:8080');

三、WebSocket封装:更易用的版本

直接用原生API有点繁琐,我们封装一个好用的工具类:

javascript 复制代码
class EasyWebSocket {
    constructor(url, options = {}) {
        this.url = url;
        this.reconnectInterval = options.reconnectInterval || 3000;
        this.maxReconnectAttempts = options.maxReconnectAttempts || 5;
        this.reconnectAttempts = 0;
        this.isManualClose = false;

        // 事件回调
        this.onMessage = options.onMessage || (() => {});
        this.onOpen = options.onOpen || (() => {});
        this.onClose = options.onClose || (() => {});
        this.onError = options.onError || (() => {});

        this.connect();
    }

    // 连接
    connect() {
        this.ws = new WebSocket(this.url);

        this.ws.onopen = () => {
            console.log('✅ WebSocket连接成功');
            this.reconnectAttempts = 0;
            this.onOpen();
        };

        this.ws.onmessage = (event) => {
            try {
                const data = JSON.parse(event.data);
                this.onMessage(data);
            } catch (e) {
                this.onMessage(event.data);
            }
        };

        this.ws.onclose = () => {
            console.log('❌ WebSocket连接关闭');
            this.onClose();

            // 自动重连
            if (!this.isManualClose &&
                this.reconnectAttempts < this.maxReconnectAttempts) {
                this.reconnectAttempts++;
                console.log(`🔄 ${this.reconnectInterval/1000}秒后重连...`);
                setTimeout(() => this.connect(), this.reconnectInterval);
            }
        };

        this.ws.onerror = (error) => {
            console.error('⚠️ WebSocket错误:', error);
            this.onError(error);
        };
    }

    // 发送消息
    send(data) {
        if (this.ws && this.ws.readyState === WebSocket.OPEN) {
            const message = typeof data === 'string' ? data : JSON.stringify(data);
            this.ws.send(message);
            return true;
        }
        console.warn('⚠️ WebSocket未连接,无法发送消息');
        return false;
    }

    // 关闭连接
    close() {
        this.isManualClose = true;
        if (this.ws) {
            this.ws.close();
        }
    }

    // 获取连接状态
    getState() {
        const states = {
            [WebSocket.CONNECTING]: '连接中',
            [WebSocket.OPEN]: '已连接',
            [WebSocket.CLOSING]: '关闭中',
            [WebSocket.CLOSED]: '已关闭'
        };
        return states[this.ws?.readyState] || '未知';
    }
}

// 使用示例
const socket = new EasyWebSocket('ws://localhost:8080', {
    onMessage: (data) => {
        console.log('收到消息:', data);
    },
    onOpen: () => {
        console.log('连接建立了!');
        // 发送消息
        socket.send({ type: 'hello', content: '大家好' });
    },
    onClose: () => {
        console.log('连接断开了');
    },
    onError: (error) => {
        console.error('出错了:', error);
    },
    reconnectInterval: 3000,
    maxReconnectAttempts: 5
});

四、实际应用场景

4.1 实时聊天

javascript 复制代码
// 简单的聊天客户端
const chatSocket = new EasyWebSocket('ws://localhost:8080/chat', {
    onMessage: (data) => {
        displayMessage(data.user, data.message, data.type);
    }
});

function sendMessage(text) {
    chatSocket.send({
        type: 'message',
        content: text,
        timestamp: Date.now()
    });
}

4.2 实时数据推送

javascript 复制代码
// 股票价格实时更新
const stockSocket = new EasyWebSocket('wss://api.example.com/stocks', {
    onMessage: (data) => {
        if (data.type === 'price_update') {
            updateStockPrice(data.symbol, data.price);
        }
    }
});

4.3 在线协作

javascript 复制代码
// 文档协作编辑
const docSocket = new EasyWebSocket('wss://docs.example.com/collab', {
    onMessage: (data) => {
        switch (data.type) {
            case 'cursor_move':
                updateRemoteCursor(data.user, data.position);
                break;
            case 'text_change':
                applyRemoteChange(data.change);
                break;
        }
    }
});

五、常见问题与解决方案

Q1: 连接频繁断开怎么办?

javascript 复制代码
// 解决方案:心跳检测
class WebSocketWithHeartbeat extends EasyWebSocket {
    constructor(url, options = {}) {
        super(url, options);
        this.heartbeatInterval = options.heartbeatInterval || 30000;
        this.startHeartbeat();
    }

    startHeartbeat() {
        this.heartbeatTimer = setInterval(() => {
            if (this.ws?.readyState === WebSocket.OPEN) {
                this.send({ type: 'ping' });
            }
        }, this.heartbeatInterval);
    }

    stopHeartbeat() {
        if (this.heartbeatTimer) {
            clearInterval(this.heartbeatTimer);
        }
    }
}

Q2: 如何处理大量并发连接?

javascript 复制代码
// 使用Redis Pub/Sub实现多服务器支持
const Redis = require('redis');
const redis = Redis.createClient();

// 订阅频道
redis.subscribe('chat-channel');

// 当收到Redis消息时,广播给所有WebSocket客户端
redis.on('message', (channel, message) => {
    clients.forEach(client => {
        if (client.readyState === WebSocket.OPEN) {
            client.send(message);
        }
    });
});

// WebSocket收到消息后,发布到Redis
ws.on('message', (data) => {
    redis.publish('chat-channel', data);
});

Q3: 如何保证数据安全?

javascript 复制代码
// 连接时验证身份
const ws = new WebSocket(`wss://example.com?token=${getAuthToken()}`);

// 后端验证token
wss.on('connection', (ws, req) => {
    const token = new URL(req.url, 'http://localhost').searchParams.get('token');

    if (!validateToken(token)) {
        ws.close(4001, '认证失败');
        return;
    }

    // 认证成功,继续处理...
});

六、完整实例:在线状态同步系统

下面是一个实用的在线状态同步系统:

javascript 复制代码
/**
 * 在线状态同步系统
 * 用途:实时显示用户在线/离线状态
 */
class OnlineStatusSystem {
    constructor(serverUrl, userId) {
        this.userId = userId;
        this.serverUrl = serverUrl;
        this.onlineUsers = new Map();
        this.socket = null;

        this.init();
    }

    init() {
        this.socket = new EasyWebSocket(this.serverUrl, {
            onMessage: (data) => this.handleMessage(data),
            onOpen: () => this.onConnected(),
            onClose: () => this.onDisconnected()
        });
    }

    onConnected() {
        // 上线
        this.send({
            type: 'online',
            userId: this.userId,
            timestamp: Date.now()
        });
    }

    onDisconnected() {
        // 离线
        this.onlineUsers.delete(this.userId);
        this.render();
    }

    handleMessage(data) {
        switch (data.type) {
            case 'online':
                // 用户上线
                this.onlineUsers.set(data.userId, {
                    status: 'online',
                    lastSeen: Date.now()
                });
                break;

            case 'offline':
                // 用户离线
                this.onlineUsers.delete(data.userId);
                break;

            case 'user_list':
                // 同步用户列表
                data.users.forEach(user => {
                    this.onlineUsers.set(user.userId, user);
                });
                break;
        }

        this.render();
    }

    send(data) {
        if (this.socket) {
            this.socket.send(data);
        }
    }

    // 获取在线用户数
    getOnlineCount() {
        return this.onlineUsers.size;
    }

    // 检查用户是否在线
    isUserOnline(userId) {
        return this.onlineUsers.has(userId);
    }

    // 渲染状态(可覆盖实现)
    render() {
        console.log(`在线用户 (${this.getOnlineCount()}):`,
            Array.from(this.onlineUsers.keys())
        );
    }
}

// 使用示例
const statusSystem = new OnlineStatusSystem(
    'wss://example.com/status',
    'user123'
);

// 在HTML中显示在线状态
statusSystem.render = function() {
    const container = document.getElementById('online-users');
    container.innerHTML = `
        <h3>在线用户 (${this.getOnlineCount()})</h3>
        <ul>
            ${Array.from(this.onlineUsers.keys()).map(id =>
                `<li>${id}</li>`
            ).join('')}
        </ul>
    `;
};

七、技术栈选择参考

WebSocket服务端方案对比

方案 语言 优点 缺点 适用场景
Socket.IO Node.js 功能丰富,降级处理 较重 复杂实时应用
ws Node.js 轻量高效 需要手动处理 中小型项目
SignalR .NET 微软官方支持 平台限制 .NET项目
Django Channels Python 与Django集成 配置较复杂 Django项目
Java WebSocket Java 企业级支持 代码量大 Java企业项目

前端方案推荐

javascript 复制代码
// 方案1:原生WebSocket(简单场景)
const ws = new WebSocket('ws://localhost:8080');

// 方案2:Socket.IO客户端(复杂场景)
import io from 'socket.io-client';
const socket = io('http://localhost:8080');

// 方案3:自己封装(自定义需求)
const socket = new EasyWebSocket('ws://localhost:8080');

八、进阶学习路径

掌握了基础WebSocket后,你可以继续探索:

复制代码
WebSocket基础
    ↓
实时消息推送
    ↓
在线协作编辑
    ↓
实时游戏开发
    ↓
微服务实时通信

在这个过程中,持续学习和技术交流非常重要

💡 推荐活动 :脉脉平台的 【AI创作者xAMA第二期】 活动值得关注

虽然这个活动聚焦AI领域,但技术成长的核心逻辑是相通的

  • 🔥 与大咖交流:了解行业前沿技术趋势
  • 💬 技术讨论:WebSocket、微服务、云架构都能聊
  • 🤝 人脉拓展:连接各领域的开发者和技术专家
  • 📚 经验分享:别人的踩坑经验就是你的捷径

参与方式 :脉脉APP搜索话题 #AI创作者AMA知无不言#

技术路上一个人摸索很孤独,加入优质社区能让你少走很多弯路


九、总结

核心要点

要点 说明
WebSocket优势 实时双向通信,低延迟
应用场景 聊天、推送、协作、游戏
关键技巧 心跳检测、断线重连、数据安全
技术选型 根据项目规模和团队技术栈选择

快速检查清单

  • 了解WebSocket与传统HTTP的区别
  • 实现一个简单的WebSocket客户端
  • 实现一个WebSocket服务器
  • 掌握断线重连机制
  • 了解心跳检测原理
  • 选择合适的技术栈

相关资源


📝 作者:芊芊君子
🔗 WebSocket让实时通信变得简单

相关推荐
Ronin3051 小时前
【Linux网络】Socket编程:UDP网络编程实现ChatServer
linux·网络·udp
码农阿豪1 小时前
解决HTTP 413错误:请求实体过大(Request Entity Too Large)的终极指南
网络·网络协议·http
KG_LLM图谱增强大模型2 小时前
OpenClaw创始人官宣加入OpenAI:从开源项目到AI智能体革命-附128页电子书OpenClaw入门到精通及安装部署指南
人工智能·开源
Asher阿舍技术站2 小时前
【AI基础学习系列】四、Prompt基础知识
人工智能·学习·prompt
2401_828890642 小时前
实现扩散模型 Stable Diffusion - MNIST 数据集
人工智能·python·深度学习·stable diffusion
SailingCoder2 小时前
【 从“打补丁“到“换思路“ 】一次企业级 AI Agent 的架构拐点
大数据·前端·人工智能·面试·架构·agent
天上飞的粉红小猪2 小时前
传输层UDP&&TCP
网络·tcp/ip·udp
hqyjzsb2 小时前
企业培训ROI深度分析:如何将CAIE认证的显性与隐性成本纳入投资回报率模型
人工智能·考研·职场和发展·创业创新·学习方法·业界资讯·改行学it
大模型真好玩2 小时前
最强开源多模态大模型它来啦——一文详解Qwen3.5核心特性
人工智能·agent·vibecoding