Nodejs socket.io 在浏览器连接后,刷新一次,就多了一个连接,就是服务器和浏览器的相关操作都操作N次了,如何解决?

Nodejs socket.io 在浏览器连接后,刷新一次,就多了一个连接,就是服务器和浏览器的相关操作都操作N次了,如何解决?

浏览器: var socket = io.connect(‘http://localhost:3000’); socket.on(’*’, function(){}); 这样,

服务器: io.sockets.on(‘connection’, function(socket){ console.log(‘id:’+socket.id);}); 这样,但是这段代码是放在app.get(’/’, function(){});的function里面的

然后我每次我每次刷新浏览器,就输出多次这个了,比如我刷新了3次,就会输出4次这样, 同理,客户端的代码也执行这么多次,究竟为什么这样的,但如果我不放在app.get里面就没错了,求解

另外,为什么每次刷新浏览器,socket.id都不同的?


6 回复

解决方案

你遇到的问题是因为每次刷新浏览器时,都会重新加载页面并重新建立一个新的Socket.IO连接。这会导致服务器上累积多个连接。为了解决这个问题,你可以通过检查已存在的连接来避免重复连接。

示例代码

客户端代码

// 浏览器
var socket;
document.addEventListener('DOMContentLoaded', (event) => {
    socket = io.connect('http://localhost:3000');
    socket.on('*', function(){});
});

服务器代码

// 服务器
const io = require('socket.io')(server, {
    transports: ['polling', 'websocket'] // 确保支持多种传输方式
});

let connectedClients = new Set();

io.on('connection', (socket) => {
    console.log(`id: ${socket.id}`);
    
    // 检查是否已经存在相同的连接ID
    if (!connectedClients.has(socket.id)) {
        connectedClients.add(socket.id);
        
        // 连接逻辑
        socket.emit('welcome', '欢迎来到聊天室!');
        
        socket.on('disconnect', () => {
            connectedClients.delete(socket.id);
            console.log(`id: ${socket.id} 断开连接`);
        });
    } else {
        console.log(`重复连接 id: ${socket.id}`);
        socket.disconnect();
    }
});

解释

  1. 客户端代码:确保只在DOM加载完成后创建一个socket对象,并且不要每次都重新创建。
  2. 服务器代码:使用一个Set来存储所有已连接的客户端ID。当一个新的连接到达时,检查这个Set中是否存在该ID。如果不存在,则将该ID添加到Set中,并处理正常的连接逻辑。如果存在,则说明这是一个重复连接,可以断开这个连接或采取其他适当的措施。

关于 socket.id 的不同

socket.id 是每个连接的唯一标识符。当你刷新浏览器时,会创建一个新的连接,因此会产生一个新的socket.id。这是因为每次页面刷新时,浏览器会重新打开一个新的WebSocket连接。如果你希望在页面刷新时保持同一个连接,你需要在客户端维护一个持久化的状态(例如,通过LocalStorage)来跟踪连接状态,并在页面加载时尝试重用现有的连接。


首先你不也能把io.sockets.on放到app.get(’/’, function(){})里; 其次,本来没刷新一次页面就会新产生一个socket的对象,原来的连接等待超时后disconnect,之后删除

嗯,你说的第一个我已经改过来了 关于第二个,在刷新的时候我怎样才能把那个socket disconnect掉啊?

只要游览器断开和socket.io的连接,马上就会发出disconnect事件。也就是说,你刷新一个接连了socket.io的页面,那么这次的socket等于就自动disconnect了

那我想识别出这个身份呢?就是说是同一个人的?

你的问题涉及到Node.js和Socket.IO的一个常见陷阱。当你将Socket.IO的连接处理代码放置在app.get()路由处理器中时,每次浏览器发起一个新的HTTP请求(如页面刷新),该路由处理器都会被调用,从而导致Socket.IO重复创建新的连接。

解决方案

你应该将Socket.IO的连接处理代码独立于HTTP请求之外。确保你的Socket.IO连接逻辑只运行一次,并且是在服务器启动时初始化。

示例代码:

服务器端代码 (server.js):

const express = require('express');
const http = require('http');
const socketIo = require('socket.io');

const app = express();
const server = http.createServer(app);
const io = socketIo(server);

io.on('connection', (socket) => {
    console.log(`User connected with id: ${socket.id}`);
    
    socket.on('disconnect', () => {
        console.log(`User disconnected with id: ${socket.id}`);
    });
});

// 静态文件服务
app.use(express.static(__dirname));

server.listen(3000, () => {
    console.log('Server is running on port 3000');
});

客户端代码 (index.html):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Socket.IO Example</title>
</head>
<body>
    <script src="/socket.io/socket.io.js"></script>
    <script>
        const socket = io();

        // 监听事件或发送消息
        socket.on('*', (msg) => {
            console.log(msg);
        });

        // 可以在这里添加更多客户端逻辑
    </script>
</body>
</html>

解释

  1. 分离Socket.IO逻辑: 将Socket.IO的逻辑从Express路由中分离出来。Socket.IO应该在服务器启动时初始化,并独立于任何HTTP请求处理。

  2. 静态文件服务: 使用express.static来提供静态文件服务,确保客户端可以加载HTML、JavaScript等资源。

通过这种方式,无论用户刷新多少次,Socket.IO只会创建一个连接,避免了多次连接的问题。

回到顶部