比较WebSocket、SSE和轮询:实时通信

WebSocket、Server-Sent Events(SSE)和轮询(Polling)是常用的实现实时通信的技术。本文将深入比较这三种技术,分析它们的特点、工作原理以及优劣势。

WebSocket

特点:

  • 提供全双工通信,允许服务器和客户端在同一时间发送和接收数据。

  • 单个持久连接实现,通过事件驱动的方式进行通信。

优势:

  • 低延迟、高效,适用于需要频繁更新的应用,如在线游戏、聊天应用等。

劣势:

  • 需要较复杂的实现和支持。

示例: 前端(JavaScript):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        const socket = new WebSocket('ws://10.254.67.2:8081/connection/');

        socket.addEventListener('message', (event) => {
            console.log('收到消息:', event.data);
        });

        socket.onopen = (event) => {
            console.log('WebSocket connection opened');
            // 在这里发送你的消息
            socket.send('Hello, WebSocket!');

        };
        // setInterval(() => {
        //         socket.send(Math.random());
        //     }, 1000);
    </script>
</body>
</html>

后端(Node.js和ws库):

const express = require('express');
const WebSocket = require('ws');
const path = require('path');

// 创建Express应用程序
const app = express();

// 设置静态文件服务
app.use(express.static(path.join(__dirname, 'static')));

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

// 保存客户端连接的集合
const clients = new Set();

wss.on('connection', (socket) => {
  console.log('WebSocket client connected');

  // 将新连接添加到集合中
  clients.add(socket);

  socket.on('message', (message) => {
    console.log('Received message:', message);
    socket.send('Server received your message: ' + message);
  });

  socket.on('close', () => {
    console.log('WebSocket client disconnected');
    // 在连接关闭时,从集合中移除连接
    clients.delete(socket);
  });
});

// 创建HTTP服务器
const server = app.listen(8081, () => {
  console.log('Backend server is running on port 8081');
});

// 将WebSocket服务器附加到HTTP服务器
server.on('upgrade', (request, socket, head) => {
  wss.handleUpgrade(request, socket, head, (socket) => {
    wss.emit('connection', socket, request);
  });
});

// 定时发送消息给所有客户端
setInterval(() => {
  const message = 'This is a server push message';
  // 遍历所有客户端连接并发送消息
  clients.forEach((client) => {
    client.send(message);
  });
}, 5000);

Server-Sent Events (SSE)

特点:

  • 仅支持服务器向客户端单向推送数据。

  • 使用HTTP协议,通过单个长连接发送事件流到客户端。

优势:

  • 简单易用,无需额外的库或协议支持。

劣势:

  • 无法实现双向通信。

示例: 前端(JavaScript):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        const eventSource = new EventSource('/sse');

        eventSource.onmessage = (event) => {
            console.log('股票价格更新:', event.data);
        };

        eventSource.onerror = (error) => {
            console.error('发生错误:', error);
        }
    </script>
</body>
</html>

后端(Node.js和Express框架):

// 引入所需的模块
const express = require('express');
const http = require('http');

// 创建 Express 应用和 HTTP 服务器
const app = express();

// 静态资源中间件,将静态资源放在 static 文件夹下
app.use(express.static('static'));

app.get('/sse', (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  setInterval(() => {
    const price = Math.random() * 100;
    res.write(`data: 文字${price}\n\n`);
  }, 5000);
});

// 启动服务器
const PORT = 3333;
app.listen(PORT, () => {
  console.log(`服务器运行在 http://localhost:${PORT}`);
});

轮询 (Polling)

特点:

  • 客户端定期向服务器发送请求,检查是否有新数据。

  • 分为短轮询和长轮询两种。

优势:

  • 兼容性好,适用于不支持WebSocket或SSE的环境。

劣势:

  • 延迟较高,不适用于实时性要求较高的场景。

示例: 前端(JavaScript):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        let interval = setInterval(() => {
            fetch('/polling')
                .then(response => response.json())
                .then(data => {
                console.log('最新天气:', data);
                })
                .catch(error => {
                if(interval){
                    clearInterval(interval)
                }
                console.error('发生错误:', error);
                });
            }, 5000);
    </script>
</body>
</html>

后端(Node.js和Express框架):

// 引入所需的模块
const express = require('express');
const http = require('http');

// 创建 Express 应用和 HTTP 服务器
const app = express();

// 静态资源中间件,将静态资源放在 static 文件夹下
app.use(express.static('static'));

// 轮询示例
app.get('/polling', (req, res) => {
  console.log('轮询连接成功!');

  // 模拟异步数据更新
  setTimeout(() => {
    res.json({ message: '轮询服务器有新的数据!' });
  }, 5000); // 模拟5秒的数据更新间隔
});

// 启动服务器
const PORT = 3338;
app.listen(PORT, () => {
  console.log(`服务器运行在 http://localhost:${PORT}`);
});

结论

选择适当的实时通信技术取决于项目的具体需求和技术环境。WebSocket适用于需要实时双向通信的场景,SSE适用于服务器主动向客户端推送数据的情况,而轮询则是一个兼容性较好的备选方案。需要根据项目的实际情况权衡每种技术的优劣势,以达到最佳的实时通信效果。

代码地址

https://github.com/tomorrowzjz/polling

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容