即时通信

轮询与长轮询

轮询

客户端定时向服务器发送Ajax请求,服务器接到请求后,无论数据是否有变动,都返回响应信息并关闭连接。

优点:实现简单。

缺点:浪费带宽和服务器资源,新数据响应会有延迟。

长轮询

客户端发送请求,服务端在没有新的返回数据情况下不会立即响应,而会挂起,直到有数据变化或即将超时,返回响应信息。

优点:相对轮询,节约带宽。

缺点:在没有数据的时候在服务端挂起,会一直占用服务端资源。

轮询应用:

扫码登陆:pc端展示二维码,一直轮询问服务端二维码是否过期,或者用户已经用手机app扫码成功。

SSE(Server Send Event)服务器推送

一个客户端获取新的数据通常需要发送一个请求到服务器,也就是向服务器请求的数据。使用 server-sent 事件,服务器可以在任何时刻向我们的客户端推送数据和信息。这些被推送进来的信息可以在这个客户端上作为 Events + data 的形式来处理。

参考:https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events

客户端

EventSource 类

使用 EventSource 类接口来完成请求。

//请求路由
let eventSource = new EventSource('/users');
// 监听数据返回事件
eventSource.addEventListener('users', function (e) {
    console.log(`users`, e);
    let users = JSON.parse(e.data);
})

参考:https://developer.mozilla.org/en-US/docs/Web/API/EventSource

服务端

头信息

router.get('/users', async (ctx, next) => {
    //会一直向前端发送最新数据
    let users = JSON.parse(fs.readFileSync('./data/users.json', 'utf-8'));
    //需要设置EventSource对应的头信息
    ctx.set('Content-Type', 'text/event-stream');
    let eventStreamData = JSON.stringify(users);
    //EventSource的数据格式:事件名称 和数据
    ctx.body = `event: users\ndata:${eventStreamData}\n\n`;
})

WebSocket

WebSocketHTML5 开始提供的一种在单个连接上进行全双工通讯的协议。

使用协议:ws ,其基于 HTTP 协议进行数据传输,但是会持久化链接和状态。

socket.io

可以参照官网实现聊天室功能。https://socket.io/

一个简单示例,可以实现浏览器多个tab传输数据
npm init -y
npm i express
npm i socket.io

html页面 index.html

<body>
    <ul id="messages"></ul>
    <form id="form" action="">
        <input id="input" autocomplete="off" /><button>Send</button>
    </form>
    <script src="/socket.io/socket.io.js"></script>
    <script>
        const socket = io();
        const form = document.getElementById('form');
        const input = document.getElementById('input');
        const messages = document.querySelector('#messages');

        form.addEventListener('submit', function (e) {
            e.preventDefault();

            if (input.value) {
                // 使用 websocket 向服务器发送数据
                socket.emit('chat message - client', input.value);
                input.value = '';
            }
        });

        socket.on('chat message - server', (msg) => {
            // 接收到 服务器 推送的 msg,并显示在页面聊天区域中
            console.log(msg);
            const item = document.createElement('li');
            item.textContent = msg;
            messages.appendChild(item);
            window.scrollTo(0, document.body.scrollHeight);
        })
    </script>
</body>

服务端
node服务 index.js

const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);

app.get('/', (req, res) => {
    res.sendFile(__dirname + '/index.html');
});

// 监听事件
// 每一个独立的客户端和服务器建立连接以后,会生成一个socket对象,
//该对象保存了两个独立连接的相关信息和对应的方法,当前这个客户端与服务器的通信都是基于给对象来进行的
let sockets = [];

io.on('connection', (socket) => {
    console.log(`有客户端通过websocket连接了`);
    sockets.push(socket);
    // 监听 chat message 事件
    socket.on('chat message - client', (msg) => {
        console.log('message: ' + msg);
        // 对当前这个 socket 进行 emit
        socket.emit('chat message - server', msg);
        // 对除了自己全局广播消息
        socket.broadcast.emit('chat message - server', msg);
    })
})

server.listen(3000, () => {
    console.log('listening on *:3000');
});

可以通过WS筛选查看链接详情


image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容