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

时间:2016-12-07 16:06:49

标签: javascript node.js sockets socket.io real-time

我在服务器端运行以下代码,一切正常。但是,我想在static void SetIPv6State(Guid interfaceId, bool state) { var scope = new ManagementScope("\\\\.\\ROOT\\StandardCimv2"); var query = new ObjectQuery("SELECT * FROM MSFT_NetAdapterBindingSettingData"); var methodName = state ? "Enable" : "Disable"; using (var searcher = new ManagementObjectSearcher(scope, query)) using (var bindings = searcher.Get()) { var binding = bindings.Cast<ManagementObject>().Single(obj => (string)obj["InstanceID"] == interfaceId.ToString("B").ToUpper() + "::ms_tcpip6"); var parameters = binding.GetMethodParameters(methodName); binding.InvokeMethod(methodName, parameters, new InvokeMethodOptions()); } } 标签之间保持相同的连接,因为当我打开一个新标签时,看起来我已经与第一个标签断开连接......那么,我该如何保持相同的连接?

client.js

n

app.js

socket.emit("connected", {user: inputUser.val()};

更新: 上面的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!"); }); 事件运行正常......所以我根据答案尝试了typing事件:

typing

但它出现以下错误:

  

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

     

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

Update²: 要解决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!"); }); 事件错误,我只需更改为:

typing

5 个答案:

答案 0 :(得分:4)

在同一浏览器中的多个选项卡之间没有简单的方法来共享单个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!");
});

如果您需要users对象中包含socket对象,那么您可以将用户对象中存储的内容更改为Set个套接字,如下所示:< / p>

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!");
});

答案 1 :(得分:1)

我的解决方案是将套接字连接到具有特定用户 ID 的房间。

io.on('connection', async (socket) => {

socket.join('user:' + socket.handshake.headers.uid) // The right way is getting `uid` from cookie/token and verifying user


})

一个优势是向特定用户发送数据(发送到所有标签)

io.to('user:' + uid).emit('hello');

希望对你有帮助!

答案 2 :(得分:0)

对于仍然有此问题的任何人。这是我固定的方式。 让我解释。 页面刷新或打开新选项卡后,套接字就不再在乎了,因此每次都打开一个新连接。这多于利弊。解决此问题的最佳方法是在服务器端,一旦用户使用他或她的用户名登录,您就可以将该名称以及查询选项发送到客户端,以便可以用作唯一标识符。在我的情况下,我使用了令牌

this.socket = io.connect(`${environment.domain}` , {
      query: {token: this.authservice.authToken}
    });

然后在服务器端,您可以为键和值数组创建一个空数组。用户的用户名将用作键,而相应的套接字数组将用作值。就我自己而言,就像我说过我使用令牌

const users = [ ]
socket.nickname = (decoded token username);
users[socket.nickname] = [socket];

然后,您可以执行一个简单的逻辑来检查用户是否已存在于数组中,如果存在,则将新的套接字推送到用户的数组中

if ( user.username in users) {
                    console.log('already exists')
                    users[user.username].push(socket);
                } 

如果需要的话,只需创建一个新密钥并添加套接字作为密钥即可。(确保它是一个数组,因为用户可以始终使用相同的帐户刷新或打开一个新选项卡,并且您不希望传递聊天消息在一个标签中而不在另一个标签中投放

else {
                    socket.nickname = username;
                    users[socket.nickname] = [socket];

                }

然后发出一条消息,您只需在数组中循环并相应地发出该消息。这样,每个标签都会收到消息

socket.on('chat', (data) => {

            if (data.to in users) { 

                for(let i = 0; i < users[data.to].length; i++) {
                    users[data.to][i].emit('chat', data)
                }
                for(let i = 0; i < users[data.user].length; i++) {
                    users[data.user][i].emit('chat', data)
                }


            }
       })

您还可以添加一个断开逻辑,也可以从用户阵列中删除套接字以节省内存,因此,仅活动区域中当前打开的选项卡和关闭中的选项卡被删除。我希望它能解决您的问题

答案 3 :(得分:0)

我相信最好的方法是为用户创建一个通道,并根据其ID对其进行唯一设置,因此,当您需要接收或发送内容时,请使用该通道,并且连接到它的每个套接字都将接收。

答案 4 :(得分:0)

另一种解决方案是将标志保存到localStorage并使用eventListener更改localStorage。 存在另一个连接时请勿连接。 并将邮件保存在本地存储中,以便通过“主”标签发送。