Управление несколькими вкладками (но одним и тем же пользователем) в socket.io

У меня возникают проблемы с socket.io, и я понятия не имею, как его решить. У меня есть приложение с системой входа в систему с socket.io для управления взаимодействиями пользователей. Также у меня есть массив для управления всеми активными сеансами websocket. Этот массив хранит пару session.id = > имя пользователя.

Проблемы начинаются, когда пользователь открывает новую вкладку с той же страницей (или другой страницей, использующей websocket). Это приведет к дублированию имени пользователя в массиве.

{id1, username}
{id2, username}

Когда сокет отправляет сообщение пользователю, он отправляет только первому идентификатору сеанса массива, поэтому только одна вкладка получает сообщение.

Я попытался изменить идентификатор сокета нового соединения, чтобы он соответствовал другому, но он не работает.

socket.id = sessionId of the other websocket;

Я думаю, что еще одно решение - отправить сообщение на все открытые сессии, но я думаю, что это не лучший способ сделать это.

Спасибо.

Ответы

Ответ 1

Похоже, вы можете ссылаться на идентификатор сокета в своем вопросе, а не на идентификатор сеанса. Если у вас есть экспресс-сессия, вы можете использовать идентификатор сеанса, который будет одинаковым независимо от того, сколько вкладок открыто, если они используют один и тот же браузер, а не в режиме "private". Взгляните на этот вопрос, как включить сеансы в socket.io.

socket.io и сеанс?

Update: Когда вы сохраняете идентификатор сеанса, вы связываете его с псевдонимом пользователя и подключенными сокетами. Затем вы можете выполнять итерацию через каждый сокет и отправлять сообщение. Что-то вроде следующего:

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

Когда устанавливается другое соединение, вы вводите новый идентификатор сокета в массив socketIds, а когда пользователь отключается, вы удаляете идентификатор.

Другим вариантом может быть только одна вкладка для каждого пользователя за сеанс. Вы можете сохранить один идентификатор socketId и когда новый сокет подключается для одного и того же пользователя, вы можете отключить исходный сокет и использовать новый.

Ответ 2

Вы можете использовать хеш:

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

и проверьте io.sockets.on('connection',..), существует ли сокет под этим ключом.

Если это так, вы можете выполнить sessionHash['userName'].disconnect(); на нем и сохранить новый сокет.

Ответ 3

Я знаю, что прошло много времени с тех пор, как вы спросили об этом, но только 4 назад я опубликовал модуль для node js, express и socket.io, который управляет тем, что вам нужно. Проверьте использование и пример, надеюсь, вы найдете этот модуль полезным!

Вы можете установить его через NPM socket.io.users Это модуль node js для приложений socket.io. Один пользователь на клиента.

Некоторые из кода использования

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 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 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..

Ответ 4

Внутренняя библиотека может использоваться для совместного использования и управления соединением 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