Управление несколькими вкладками (но одним и тем же пользователем) в 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