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让实时通信变得简单

相关推荐
To_OC4 小时前
搞懂 Token 和 Embedding 后,我终于明白大模型是怎么 "读" 文字的
人工智能·llm·agent
冬奇Lab6 小时前
每日一个开源项目(第139篇):Voicebox - 本地运行的开源 ElevenLabs 替代品
人工智能·开源·资讯
冬奇Lab6 小时前
Skill 系列(03):Skill 设计范式——5 个模式让输出从混沌到可预测
人工智能·开源·agent
IT_陈寒8 小时前
Python搞不定字符串编码?这破玩意坑我两小时!
前端·人工智能·后端
用户2530171996279 小时前
第6篇:从技术到产品 — Ghost Proxifier 的设计哲学
网络协议
大模型真好玩10 小时前
什么是Loop Engineering?最通俗易懂的Loop Engineering核心概念
人工智能·agent·deepseek
用户25301719962710 小时前
第3篇:注入的艺术 — Ghost Proxifier 核心架构拆解
网络协议
叁两10 小时前
前端转型AI Agent该如何学习?(前置篇)
前端·人工智能·node.js
LaiYoung_10 小时前
🎁 送你一套超好用超实用的 FE AI-Coding Skills
前端·人工智能·开源