nodejs- socket.io服务器为所有用户推送相同的数据

ver*_*n 2 7 sockets node.js socket.io

我做的socket.io实现是错误的.我正在尝试对mysql数据实现长轮询.

对于此演示,我将为连接到我创建的长轮询服务器的每个用户提取用户数据.每个用户将其唯一的user_id传递给服务器以获取与他/她相关的数据.(在真实应用中,我想获取用户通知)

用户连接到服务器,服务器也从数据库进行长轮询.但问题是,即使我从客户端传递了唯一的ID,同样的数据也被推回到客户端.

用户1通过了id 5,用户2通过了id 3.这两个用户获得的数据与响应相同(用户1的数据)

这是客户端代码:

var user_id = 5; //hardcoded for now, but in real its fetched from a form
var params = {
    userId: user_id,
};
// create a new websocket
var socket = io.connect('http://localhost:8000', { query: params });

// on message received we print all the data inside the #container div
socket.on('notification', function (data) {
    console.log(data);

});
Run Code Online (Sandbox Code Playgroud)

这是服务器端代码:

var app = require('http').createServer(handler),
    io = require('socket.io').listen(app),
    fs = require('fs'),
    mysql = require('mysql'),
    connectionsArray = [],
    connection = mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: '',
        database: 'dumydb',
        port: 3306
    }),
    POLLING_INTERVAL = 5000,
    pollingTimer;

// If there is an error connecting to the database
connection.connect(function (err) {
    // connected! (unless `err` is set)
    if (err) {
        console.log(err);
    }
});

// creating the server ( localhost:8000 )
app.listen(8000);

// on server started we can load our client.html page
function handler(req, res) {
    fs.readFile(__dirname + '/client.html', function (err, data) {
        if (err) {
            console.log(err);
            res.writeHead(500);
            return res.end('Error loading client.html');
        }
        res.writeHead(200);
        res.end(data);
    });
}

// creating a new websocket to keep the content updated without any AJAX request
io.sockets.on('connection', function (socket) {

    var userId = socket.handshake.query.userId;
    // starting the loop only if at least there is one user connected
    if (!connectionsArray.length) {
        pollingLoop(userId);
    }

    socket.on('disconnect', function () {
        var socketIndex = connectionsArray.indexOf(socket);
        console.log('socketID = %s got disconnected', socketIndex);
        if (~socketIndex) {
            connectionsArray.splice(socketIndex, 1);
        }
    });

    console.log('A new socket is connected!');
    connectionsArray.push(socket);

});

var pollingLoop = function (userId) {
    var params = [userId];
    // Doing the database query
    var tempQuery = `SELECT full_name FROM users WHERE id=?`;
    var query = connection.query(tempQuery, params),
        users = []; // this array will contain the result of our db query

    // setting the query listeners
    query
        .on('error', function (err) {
            // Handle error, and 'end' event will be emitted after this as well
            updateSockets(err);
        })
        .on('result', function (user) {
            // it fills our array looping on each user row inside the db
            users.push(user);
        })
        .on('end', function () {
            // loop on itself only if there are sockets still connected
            if (connectionsArray.length) {

                pollingTimer = setTimeout(function () { pollingLoop(userId) }, POLLING_INTERVAL);

                updateSockets({
                    users: users
                });
            } else {
                console.log('The server timer was stopped because there are no more socket connections on the app')
            }
        });
};

var updateSockets = function (data) {
    // adding the time of the last update
    data.time = new Date();
    // sending new data to all the sockets connected
    connectionsArray.forEach(function (tmpSocket) {
        tmpSocket.volatile.emit('notification', data);
    });
};

console.log('Please use your browser to navigate to http://localhost:8000');
Run Code Online (Sandbox Code Playgroud)

这是我正在遵循的教程:链接

任何人都可以帮我弄清楚为什么同样的数据被推送给所有用户?谢谢!

更新1

我尝试了Theo和Abdul Rab Memon提供的解决方案更改了我的updateSockets(),但现在数据只被推送到连接的第一个客户端.我做了一个console.log()看看这个:

在此输入图像描述

更新2:package.json

{
  "name": "nodejs-MySQL-push-notifications-demo",
  "version": "1.0.0",
  "description": "nodejs-MySQL-push-notifications-demo",
  "main": "server.js",
  "dependencies": {
    "express": "^4.16.2",
    "mysql": "~2.5.4",
    "socket.io": "~1.3.2"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "repository": {
    "type": "git",
    "url": "git://github.com/GianlucaGuarini/nodejs-MySQL-push-notifications-demo.git"
  },
  "author": "Gianluca Guarini",
  "license": "BSD-2-Clause",
  "bugs": {
    "url": "https://github.com/GianlucaGuarini/nodejs-MySQL-push-notifications-demo/issues"
  },
  "homepage": "https://github.com/GianlucaGuarini/nodejs-MySQL-push-notifications-demo"
}
Run Code Online (Sandbox Code Playgroud)

Abd*_*mon 6

var app = require('http').createServer(handler),
    io = require('socket.io').listen(app),
    fs = require('fs'),
    mysql = require('mysql'),
    connectionsArray = [],
    connection = mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: '',
        database: 'dumydb',
        port: 3306
    }),
    POLLING_INTERVAL = 5000,
    pollingTimer;

// If there is an error connecting to the database
connection.connect(function (err) {
    // connected! (unless `err` is set)
    if (err) {
        console.log(err);
    }
});

// creating the server ( localhost:8000 )
app.listen(8000);

// on server started we can load our client.html page
function handler(req, res) {
    fs.readFile(__dirname + '/client.html', function (err, data) {
        if (err) {
            console.log(err);
            res.writeHead(500);
            return res.end('Error loading client.html');
        }
        res.writeHead(200);
        res.end(data);
    });
}

// creating a new websocket to keep the content updated without any AJAX request
io.sockets.on('connection', function (socket) {

    var userId = socket.handshake.query.userId;
    connectionsArray.push(socket);
    // starting the loop only if at least there is one user connected
    if (connectionsArray.length) {
        var socketIndex = connectionsArray.indexOf(socket);
        pollingLoop(userId, socketIndex);
    }

    socket.on('disconnect', function () {
        var socketIndex = connectionsArray.indexOf(socket);
        console.log('socketID = %s got disconnected', socketIndex);
        if (~socketIndex) {
            connectionsArray.splice(socketIndex, 1);
        }
    });

    console.log('A new socket is connected!');

});

var pollingLoop = function (userId, socketIndex) {
    var params = [userId];
    // Doing the database query
    var tempQuery = `SELECT full_name FROM users WHERE id=?`;
    var query = connection.query(tempQuery, params),
        users = []; // this array will contain the result of our db query

    // setting the query listeners
    query
        .on('error', function (err) {
            // Handle error, and 'end' event will be emitted after this as well
            updateSockets(err, socketIndex);
        })
        .on('result', function (user) {
            // it fills our array looping on each user row inside the db
            users.push(user);
        })
        .on('end', function () {
            // loop on itself only if there are sockets still connected
            if (connectionsArray.length) {

                pollingTimer = setTimeout(function () { pollingLoop(userId) }, POLLING_INTERVAL);

                updateSockets({
                    users: users
                }, socketIndex);
            } else {
                console.log('The server timer was stopped because there are no more socket connections on the app')
            }
        });
};

var updateSockets = function (data, socketIndex) {
    // adding the time of the last update
    data.time = new Date();
    // sending new data to all the sockets connected
    connectionsArray[socketIndex].volatile.emit('notification', data);
};

console.log('Please use your browser to navigate to http://localhost:8000');
Run Code Online (Sandbox Code Playgroud)

在updateSockets方法中,您将遍历connectionsArray并使用connectionsArray中存在的每个套接字上的数据发出'notification'事件,您需要将套接字从socket.on('connection',callback(socket))传递给pollingLoop方法,从pollingLoop到updatSocket方法.


The*_*heo 3

由于您提到您想要获取与用户相关的数据,因此您需要发送到特定的客户端套接字。为此,您需要在每次连接时保存客户端的 socket.id。你可以用这样的方法来做到这一点:

var userList = {};

io.on('connection', (socket) => {
   usersList[socket.handshake.query.userId].socket_id = socket.id;
});
Run Code Online (Sandbox Code Playgroud)

成功轮询后,您可以像这样发送给特定用户
注意可以从 pollingLoop 传递的附加参数 userId

var updateSockets = function (data, userId) {
    // adding the time of the last update
    data.time = new Date();
    // sending new data to the specific socket connected
    io.sockets.to(userList[userId].socket_id).emit('notification', data);
};
Run Code Online (Sandbox Code Playgroud)

您可以尝试使用命名空间或房间发送到群组。所以而不是

connectionsArray.forEach(function (tmpSocket) {
    tmpSocket.volatile.emit('notification', data);
});
Run Code Online (Sandbox Code Playgroud)

你可以使用命名空间

客户端代码

var socket = io.connect('http://localhost:8000/your_name_space', { query: params });
Run Code Online (Sandbox Code Playgroud)

服务器代码

io.of('/your_name_space').emit('notification', data_to_be_sent);
Run Code Online (Sandbox Code Playgroud)

群组- 请参阅此链接了解有关房间的更多信息https://socket.io/docs/rooms-and-namespaces/