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

时间:2017-11-02 10:38:50

标签: node.js sockets 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);

});

这是服务器端代码:

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');

这是我正在关注的教程:Link

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

更新1

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

enter image description here

更新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"
}

2 个答案:

答案 0 :(得分: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');

在updateSockets方法中,您将重复遍历connectionsArray并发出通知'如果事件包含在connectionsArray中存在的每个套接字上的数据,则需要将套接字从socket.on(' connection',callback(socket))传递给pollingLoop方法,并从pollingLoop传递到updatSocket方法。

答案 1 :(得分:2)

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

var userList = {};

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

成功投票后,您可以发送给这样的特定用户 请注意您可以从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);
};

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

connectionsArray.forEach(function (tmpSocket) {
    tmpSocket.volatile.emit('notification', data);
});

您可以使用命名空间

客户代码

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

服务器代码

io.of('/your_name_space').emit('notification', data_to_be_sent);

群组 - 有关会议室https://socket.io/docs/rooms-and-namespaces/的更多信息,请参阅此链接