使用Socket.io处理多个选项卡

Igo*_*gor 4 javascript sockets real-time node.js socket.io

我在服务器端使用以下代码,一切正常。但是,我想保持n选项卡之间的相同连接,因为当我打开一个新选项卡时,看起来好像已经与第一个选项卡断开连接了……那么,如何保持相同的连接?

client.js

socket.emit("connected", {user: inputUser.val()};
Run Code Online (Sandbox Code Playgroud)

app.js

var express = require("express"),
app = express(),
http = require("http").Server(app),
io = require("socket.io")(http),
users = {};

io.on("connection", function(socket) {
    socket.on("connected", function(data) {
        socket.user = data.user;

        users[socket.user] = socket;

        updateUsers();
    });

    function updateUsers() {
        io.emit("users", Object.keys(users));
    }

    socket.on("typing", function(data) {
        var userMsg = data.user;

        if(userMsg in users) {
            users[userMsg].emit("typing", {user: socket.user});
        }
    });

    socket.on("disconnect", function(data) {
        if(!socket.user) {
            return;
        }

        delete users[socket.user];

        updateUsers();
    });

});

var port = Number(process.env.PORT || 8000);

http.listen(port, function() {
    console.log("Server running on 8000!");
});
Run Code Online (Sandbox Code Playgroud)

更新typing上面的事件工作正常...所以我typing根据回答尝试了该事件:

var express = require("express"),
    app = express(),
    http = require("http").Server(app),
    io = require("socket.io")(http),
    users = {};

io.on("connection", function(socket) {
    socket.on("connected", function(data) {
        socket.user = data.user;

        // add this socket to the Set of sockets for this user
        if (!users[socket.user]) {
            users[socket.user] = new Set();
        }
        users[socket.user].add(socket);

        updateUsers();
    });

    function updateUsers() {
        io.emit("users", Object.keys(users));
    }

    socket.on("typing", function(data) {
        var userMsg = data.user;

        if(userMsg in users) {
            users[userMsg].emit("typing", {user: socket.user});
        }
    });

    socket.on("disconnect", function(data) {
        if(!socket.user) {
            return;
        }

        // remove socket for this user
        // and remove user if socket count hits zero
        if (users[socket.user]) {
            users[socket.user].delete(socket);
            if (users[socket.user].size === 0) {
                delete users[socket.user];
            }
        }

        updateUsers();
    });

});

var port = Number(process.env.PORT || 8000);

http.listen(port, function() {
    console.log("Server running on 8000!");
});
Run Code Online (Sandbox Code Playgroud)

但是它给出了以下错误:

users [userMsg] .emit(“ typing”,{user:socket.user}); ^

TypeError:users [userMsg] .emit不是一个函数

更新²:为了解决typing事件错误,我更改为:

socket.on("typing", function(data) {
    var userMsg = data.user;

    if(userMsg in users) {
        for(let userSet of users[userMsg]) {
            userSet.emit("typing", {user: socket.user});
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

jfr*_*d00 5

没有简单的方法可以在同一浏览器的多个选项卡之间共享单个socket.io连接。多个选项卡的常用模型是每个选项卡仅具有其自己的socket.io连接。

单独打开新标签页和新的socket.io连接不应导致服务器认为一切已断开连接。如果您的代码正在执行此操作,那么这就是您的代码中的错误,可能更容易修复该特定错误。

实际上,如果您要显式支持多个选项卡并能够识别同一用户可能使用了多个选项卡,则可能需要更改服务器端代码,以便它可以跟踪单个的多个套接字。用户,而不是目前的编码方式,只能跟踪每个用户一个套接字。

如果您的服务器代码确实只是想跟踪哪些用户在线,那么可以通过引用对每个用户计数来找到一种更简单的方法。我将稍后发布一个代码示例。

var express = require("express"),
app = express(),
http = require("http").Server(app),
io = require("socket.io")(http),
users = {};

io.on("connection", function(socket) {
    socket.on("connected", function(data) {
        socket.user = data.user;

        // increment reference count for this user
        if (!users[socket.user]) {
            users[socket.user] = 0;
        }
        ++users[socket.user];

        updateUsers();
    });

    function updateUsers() {
        io.emit("users", Object.keys(users));
    }

    socket.on("disconnect", function(data) {
        if(!socket.user) {
            return;
        }

        // decrement reference count for this user
        // and remove user if reference count hits zero
        if (users.hasOwnProperty(socket.user)) {
            --users[socket.user];
            if (users[socket.user] === 0) {
                delete users[socket.user];
            }
        }

        updateUsers();
    });

});

var port = Number(process.env.PORT || 8000);

http.listen(port, function() {
    console.log("Server running on 8000!");
});
Run Code Online (Sandbox Code Playgroud)

如果您需要users对象中包含socket对象,则可以将存储在用户对象中的内容更改Set为套接字,如下所示:

var express = require("express"),
app = express(),
http = require("http").Server(app),
io = require("socket.io")(http),
users = {};

io.on("connection", function(socket) {
    socket.on("connected", function(data) {
        socket.user = data.user;

        // add this socket to the Set of sockets for this user
        if (!users[socket.user]) {
            users[socket.user] = new Set();
        }
        users[socket.user].add(socket);

        updateUsers();
    });

    function updateUsers() {
        io.emit("users", Object.keys(users));
    }

    socket.on("disconnect", function(data) {
        if(!socket.user) {
            return;
        }

        // remove socket for this user
        // and remove user if socket count hits zero
        if (users[socket.user]) {
            users[socket.user].delete(socket);
            if (users[socket.user].size === 0) {
                delete users[socket.user];
            }
        }

        updateUsers();
    });

});

var port = Number(process.env.PORT || 8000);

http.listen(port, function() {
    console.log("Server running on 8000!");
});
Run Code Online (Sandbox Code Playgroud)

  • @Igor-对于您最初提出的要求,我付出了很多努力,现在您已经更改了问题。请不要这样做。尝试将您的“真实问题”放在原始问题中,这样您就不会改变别人的想法。我猜想`var userMsg = data.user;`应该是`var userMsg = socket.user;`,然后如果使用`Set`解决方案,则必须更改`users [userMsg] .emit (...)`遍历集合并发送到集合中的每个套接字,如果您要向该用户打开的所有选项卡发送相同的消息。 (3认同)