在 socket.io 中管理多个选项卡(但同一用户)

Posted

技术标签:

【中文标题】在 socket.io 中管理多个选项卡(但同一用户)【英文标题】:Manage multiple tabs (but same user) in socket.io 【发布时间】:2012-08-23 08:52:42 【问题描述】:

我在使用 socket.io 时遇到了一些问题,我不知道如何解决它。我有一个带有 socket.io 登录系统的应用程序来管理用户交互。我还有一个数组来管理所有活动的 websocket 会话。该数组存储一对 session.id => 用户名。

当用户打开具有相同页面(或使用 websocket 的不同页面)的新选项卡时,问题就开始了。这会导致数组中出现重复的用户名条目。

id1, username
id2, username

socket向用户发送消息时,只发送给数组的第一个会话id,所以只有一个tab接收消息。

我已尝试更改新连接的套接字 id 以匹配另一个,但它不起作用。

socket.id = sessionId of the other websocket;

我认为另一种解决方案是将消息发送到所有打开的会话,但我认为这不是最好的方法。

谢谢。

【问题讨论】:

【参考方案1】:

听起来您可能指的是问题中的套接字 ID,而不是会话 ID。如果您有一个快速会话,您可以使用会话 ID,只要它们使用相同的浏览器并且它不是处于“私人”模式,无论打开多少个选项卡,它都是相同的。看看这个问题,了解如何在 socket.io 中启用会话。

socket.io and session?

更新: 当您保存会话 ID 时,您会将其与用户的昵称和连接的套接字相关联。然后您可以遍历每个套接字并发送消息。类似于以下内容:

[
    sessionId: '12345', nickname: 'timmay!', socketIds: [1, 2, 3],
    sessionId: '23456', nickname: 'pete', socketIds: [4, 5, 6]
]

当另一个连接建立时,你将新的套接字 ID 推送到 socketIds 数组中,当用户断开连接时,你删除该 ID。

另一种选择可能是每个会话只允许每个用户使用一个选项卡。您可以存储单个 socketId,当新的套接字为同一用户连接时,您可以断开原始套接字并使用新的。

【讨论】:

谢谢。我现在在 socket.io (socket.handshake.sessionID) 中有会话 ID,但是我如何将消息发送到特定的 sessionid,如 io.sockets.socket(socketid).emit(...),但使用 sessionid而不是socketid? 谢谢。我懂了。最后一个问题。可以在没有 io.sockets.socket(socketid).emit(...) 循环的情况下向套接字 id 数组发送消息? 是和不是。必须有一个循环,但您不一定要编写它。您可以使用每个功能,例如下划线提供的功能。 underscorejs.org/#each @Timothy Strimple 你使用的是什么 websocket 服务器? 另一种解决方案可能是为每个 cookie 会话打开一个套接字,然后通过事件发射器通过 localStorage 从套接字监听和发送。【参考方案2】:

我知道你问这个问题已经很久了,但就在 4 年前,我发布了一个用于 node js、express 和 socket.io 的模块,它可以管理你想要的东西。查看用法和示例,希望对您有所帮助!

您可以通过 NPM 安装它socket.io.users 这是一个用于 socket.io 应用程序的节点 js 模块。每个客户一个用户。

部分使用代码

var express = require('express');
var app = express();
var server = require('http').createServer(app);
var socketUsers = require('socket.io.users');
//....
socketUsers.Session(app);//IMPORTANT 
//...
var rootIo = require('socket.io')(server); //default '/' as namespace. 
var chatIo = rootIo.of('/chat');

var rootUsers = socketUsers.Users; /* default '/' as namespace.
Each namespace       has IT's OWN users object list,
but the Id of a user of any other namespace may 
has the same value if       request comes from the same client-machine-user.
This makes   easy to keep a kind of 
synchronization between all users of all   different namespaces. */

var chatUsers = socketUsers.Users.of('/chat'); //  


rootIo.use(socketUsers.Middleware());/*IMPORTANT but no errors if you want
to  skip it for a io.of(namespace) 
that you don't want the socket.io.users' support.  */

chatUsers.use(socketUsers.Middleware());

chatUsers.on('connected',function(user)
console.log(user.id + ' has connected to the CHAT');
user.store.username = 'username setted by server side'; /*at the store
property you can store any type of properties
and objects you want to share between your user's sockets.  */
user.socket.on('any event', function(data) 
/*user.socket is the current socket, to get all connected sockets from this  
user, use: user.sockets */

);
chatIo.emit('set username',user.store.username);
);

rootUsers.on('connected',function(user)
   console.log('User has connected with ID: '+ user.id);
);



rootUsers.on('connection',function(user)
   console.log('Socket ID: '+user.socket.id+' is user with ID: '+user.id);
);

rootUsers.on('disconnected',function(user)
    console.log('User with ID: '+user.id+'is gone away :(');
);

//...server.listen blabla..

【讨论】:

模块在哪里?【参考方案3】:

你可以像这样使用哈希:

var sessionHash = ;
sessionHash['userName'] = socket;

并检查io.sockets.on('connection',..) 在该键下是否存在套接字。

如果是这样,您可以对其执行sessionHash['userName'].disconnect(); 并保存全新的套接字。

【讨论】:

我确实按照你的建议。我想为每个连接的用户只保留一个活动标签。问题是当我尝试记录旧的 sessionID(旧选项卡)和新的 sessionID(刚刚打开的选项卡)时,它们是相同的。我不明白为什么,因为我要断开旧套接字 我在尝试您的方法,但套接字(在第一个选项卡中)与套接字(在第二个选项卡中)不同,我做错了吗?【参考方案4】:

Intercom library 可用于共享和管理 socket.io 连接。

// Initialize socket.io on one tab
var socket = io.connect('//yourwebsite.com/socketio');

// Initialize intercom on all tab
var intercom = Intercom.getInstance();
intercom.bind(socket);

// Listen to an event
intercom.on('msgBroadcast', function(data)
    console.log(data);
);

// Emit an event
intercom.emit('msgBroadcast', 
    socket: true,
    message: 'Hello all!'
);

你也可以使用socketio shared webworkers

【讨论】:

以上是关于在 socket.io 中管理多个选项卡(但同一用户)的主要内容,如果未能解决你的问题,请参考以下文章

在重新连接、socket.io、node.js 时重用套接字 id

当我的网站在多个窗口中打开时,在实时事件中打开 window.open(使用 socket.io)

如何在浏览器选项卡之间共享单个 js 资源?

使用 socket.io 管理多个聊天室的正确方法是啥?

管理多个选项卡的 webapp 会话数据/控制器流

管理多个选项卡的 webapp 会话数据/控制器流