Socket.io为所有客户端分配相同的ID

我正在尝试将所有连接的客户端保存在一个对象中。 但是,正如我所知,连接的客户端都具有相同的ID。 因此,如果对象connections具有所有连接的套接字,当我尝试发送消息到connections['mac']它只是出现在我的屏幕上,由我发送给我。 这是validation码:

 app.post('/auth', function(req, res){ // routes.auth(hash, db, io, pseudoArray, connections) var username = req.body.username, password = req.body.password; if (username != "" && password != ""){ authenticate(username, password, db, hash, function(err, user){ if (user) { // Regenerate session when signing in // to prevent fixation console.log('user authenticated'); req.session.regenerate(function(){ req.session.user = user.name; req.session.success = 'Authenticated as ' + user.name + ' click to <a href="/logout">logout</a>. ' + ' You may now access <a href="/restricted">/restricted</a>.'; io.sockets.on('connection', function (socket) { socket.set('pseudo', req.session.user, function(){ pseudoArray.push(req.session.user); var sessionuser = req.session.user; socket.emit('pseudoStatus', 'ok'); connections[req.session.user] = socket; console.log("user " + req.session.user + " connected"); }); }); res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }); res.redirect('home'); }); } else { console.log('auth failed'); req.session.error = 'Authentication failed, please check your ' + ' username and password.' + ' (use "tj" and "foobar")'; res.redirect('login'); } }); } else { res.redirect('connect'); } }); 

我发送消息给其他客户端的代码:

 exports.addfriend = function(connections, io){ return function(req, res){ // var collection = db.get('go1'); var username = req.session.user; var friend = req.body.name; console.log(connections[''+friend+'']); connections[''+friend+''].emit('addRequest', username); return; } } 

我之前在路由文件中有这个authentication代码,我想我应该运行这个closuresapp.js. 我这样做,它仍然不工作,因为我想要的。 有人能告诉我我失踪了吗?

你的代码的问题是你的HTTP路由中有一个Socket.IO传入连接处理程序。 这意味着处理程序只在访问路由之后才应用,除了应该只有一个Socket.IO连接处理程序。

你需要做的是分开你的HTTP和Socket.IO处理程序,并且由于你正在使用会话,允许Socket.IO来处理授权。

首先,将您的套接字处理程序移到HTTP处理程序之外:

 app.post('/', handler); io.sockets.on('connection', handler); 

然后,定义Socket.IO授权设置以从Express获取会话对象。 假设您使用express.cookieParser()因为您有会话和会话存储,我们需要从外部引用它们:

 var MemoryStore = express.session.MemoryStore; var session_key = 'express.sid'; var session_secret = 'for signed cookies'; var session_store = new MemoryStore(); var cookieParser = express.cookieParser(session_secret); app.use(cookieParser); app.use(express.session({ secret: session_secret, store: session_store, key: session_key }); 

既然会话对象和cookieparsing器是可访问的,我们可以定义授权设置:

 io.set('authorization', function(handshake, callback) { if (handshake.headers.cookie) { cookieParser(handshake, null, function(err) { // Use depends on whether you have signed cookies // handshake.sessionID = handshake.cookies[session_key]; handshake.sessionID = handshake.signedCookies[session_key]; session_store.get(handshake.sessionID, function(err, session) { if (err || !session) { callback('Error or no session.', false); } else { handshake.session = session; callback(null, true); } }); }); } else { callback('No session cookie found.', false); } }); 

这段代码做的是检查客户端是否有会话cookie。 如果不是,则不授权Socket.IO连接。 如果是,则parsing该cookie,find关联的会话,并将该会话存储在套接字中。 现在,您可以通过套接字访问会话属性:

 app.post('/', function(req, res) { req.session.user = 'genericusername'; res.send(200); }); io.sockets.on('connection', function(socket) { var session = socket.handshake.session; session.user // genericusername }); 

至于你的代码,它会看起来如下所示:

 var http = require('http'); var express = require('express'); var app = express(); var server = http.createServer(app); var io = require('socket.io').listen(server); var MemoryStore = express.session.MemoryStore; var session_key = 'express.sid'; var session_secret = 'for signed cookies'; var session_store = new MemoryStore(); var cookieParser = express.cookieParser(session_secret); app.use(cookieParser); app.use(express.session({ secret: session_secret, store: session_store, key: session_key }); 

路由处理程序:

 app.post('/auth', function(req, res) { var username = req.body.username, var password = req.body.password; if (username != '' && password != '') { authenticate(username, password, db, hash, function(err, user) { if (user) { req.session.regenerate(function() { req.session.user = user.name; req.session.success = 'Authenticated as ' + user.name + ' click to <a href="/logout">logout</a>. You may now access <a href="/restricted">/restricted</a>.'; res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }); res.redirect('/home'); }); } else { req.session.error = 'Authentication failed, please check your username and password. (use "tj" and "foobar")'; res.redirect('/login'); } }); } else { res.redirect('/connect'); } }); 

然后Socket.IOconfiguration:

 io.set('authorization', function(handshake, callback) { if (handshake.headers.cookie) { cookieParser(handshake, null, function(err) { // Use depends on whether you have signed cookies // handshake.sessionID = handshake.cookies[session_key]; handshake.sessionID = handshake.signedCookies[session_key]; session_store.get(handshake.sessionID, function(err, session) { if (err || !session) { callback('Error or no session.', false); } else { handshake.session = session; callback(null, true); } }); }); } else { callback('No session cookie found.', false); } }); io.sockets.on('connection', function(socket) { var session = socket.handshake.sessionl socket.set('pseudo', session.user, function() { socket.emit('pseudoStatus', 'ok'); connections[session.user] = socket; }); }); 

你有一个io.sockets.on('connection'...在一个用户login中,所以每次用户login时,都会有另一个监听器被添加。

所以它可能看起来像这样(有人login,然后连接到套接字)

用户1login用户1连接到套接字(伪自己)

用户2login用户2连接到套接字(虚拟为用户1,然后虚拟为用户2)

用户3login用户3连接到套接字(假设为1,2,然后3

如果用户1刷新页面,那么他将被伪造成1,2,3

每次有人login时,问题越来越多。

您需要监听多次发生的function之外的连接。

我通常做类似以下的事情

用英语:用户加载一个页面,他连接到socket io,然后他做了一个ajax $ .get,这样服务器可以使用他的会话给他一个授权他的套接字的令牌。 然后他发送令牌,并且服务器知道该套接字已被授权。

 app.get('/socket_token', function(req, res, next){ var socket_token = Math.random();/* probably want to use crypto here instead*/ mysql.query('update users set users.socket_token = ? where users.id = ?', [ socket_token, req.session.userId], function(err, result){ if(result) res.json({userId: req.session.userId, socket_token: socket_token}); else res.send('DOH!'); }); }); global.all_my_sockets = [] io.sockets.on('connnection', function(socket){ socket.emit('hey_you_are_connected'); socket.on('authorize', function(credentials, callback){ if(credentials.userId) mysql.query('select * from users where id = ?', [credentials.userId], function(err, user){ if(user.socket_token == credentials.socket_token){ socket.set('authorized', true); socket.set('userId', user.id); // This is probably bad since what if he has 2 browser windows open? all_my_sockets[user.id] = socket callback('that socket token is authorized'); } else { //handle it callback('that socket token is no good'); } }) }); socket.on('disconnect', function(){ socket.get('userId', function(id){ if(id) delete all_my_sockets[id]; }); }); }) 

并在客户端

 socket = io.connect(); socket.on('hey_you_are_connected', function(){ $.get('/socket_token', function(credentials){ socket.emit('authorize_token', credentials, function(res){ console.log(res); // did we authorize socket? }); }); }); 

我把这个打在了我头上,所以可能会出现错误,但是它应该和你正在做的事很接近。

因此,在all_my_sockets [id]中保存套接字时会遇到一些问题,即每个用户只能有一个套接字,如果他们打开了多个浏览器呢?

你应该尝试以不同的方式构造你的代码,所以你不需要全局的套接字,否则,只需将它们推送到数组,以便每个用户都可以存在多个套接字。

 all_my_sockets.push(socket); ... socket.on('disconnect', function(){ if( all_my_sockets.indexOf(socket) != -1 ) all_my_sockets.splice( all_my_sockets.indexOf(socket), 1 ) }) 

如果你将每个套接字都推送到数组中,那么在它们被授权之前,要真正find套接字,就必须经过每一个套接字:

 _.each(all_my_sockets, function(socket){ socket.get('userId', function(userId) { if(userId) doSomething(socket) else doSomethingUnAuthorized(socket) }); }); 

显然这是非常缓慢的,这就是为什么没有很多人将套接字节省到这样一个全球性的地方。 试着用更多的callback来做你想做的事情,从头开始重新思考这个问题。 或者把它作为黑客,直到你获得更多的stream量,这成为一个性能问题。 🙂