我正在尝试构建一个客户端,它将id(例如电子邮件)发送到服务器上的nodejs程序。电子邮件实际上是登录用户。
nodejs程序应该继续使用该电子邮件地址的相关数据更新客户端上的特定div(比如每隔3秒推送一次数据)。
同样应该在多台机器上完成,其中每台机器都有单独的人员通过电子邮件登录。像gmail上发生的事情。
我已按如下方式构建它,但是当我从多个客户端打开它时,最新客户端(电子邮件)的值会覆盖以前的客户端值和所有客户端显示数据,仅用于最新的电子邮件。
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
fs = require('fs'),
mysql = require('mysql'),
connectionsArray = [],
profile_id,
last_count = 0, //this variable is to check previous count value
connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '', //put your own mysql pwd
database: 'test', //put your database name
port: 3306
}),
POLLING_INTERVAL = 1000,
pollingTimer;
// If there is an error connecting to the database
connection.connect(function(err) {
// connected! (unless `err` is set)
console.log(err);
});
console.log('DB connected');
// 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 + '/indexnew.html', function(err, data) {
if (err) {
console.log(err);
res.writeHead(500);
return res.end('Error loading client.html');
}
console.log('File loaded');
res.writeHead(200);
res.end(data);
});
}
/*
* HERE IT IS THE COOL PART
* This function loops on itself since there are sockets connected
* to the page. Upon Update it only emits the notification if
* the value has changed.
* Polling the database after a constant interval
*/
var pollingLoop = function() {
sql = "SELECT count(*) as c FROM activity_log WHERE notified=0 and (profile_id = '" + profile_id + "')";
console.log(sql);
// Doing the database query
var query = connection.query(sql),
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
console.log(err);
updateSockets(err);
})
.on('result', function(count) {
// it fills our array looping on each user row inside the db
users.push(count);
// loop on itself only if there are sockets still connected
if (connectionsArray.length) {
pollingTimer = setTimeout(pollingLoop, POLLING_INTERVAL);
updateSockets({
users: users,
count: count.c
});
}
})
};
// creating a new websocket to keep the content updated without any AJAX request
io.sockets.on('connection', function(socket) {
console.log('Connected');
//This variable is passed via the client at the time of socket //connection, see "io.connect(..." line in client.html
profile_id = socket.handshake.query.profile_id;
console.log('Number of connections:' + connectionsArray.length);
// starting the loop only if at least there is one user connected
if (!connectionsArray.length) {
pollingLoop();
}
socket.on('disconnect', function() {
var socketIndex = connectionsArray.indexOf(socket);
console.log('socket = ' + socketIndex + ' disconnected');
if (socketIndex >= 0) {
connectionsArray.splice(socketIndex, 1);
}
});
console.log('A new socket is connected!');
connectionsArray.push(socket);
});
var updateSockets = function(data) {
if (last_count != data.count) {
// 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);
});
}
last_count = data.count;
};
indexnew.html
<html>
<head>
<title>Push notification long polling server streaming on a MySQL db</title>
<style>
dd,
dt {
float: left;
margin: 0;
padding: 5px;
clear: both;
display: block;
width: 100%;
}
dt {
background: #ddd;
}
time {
color: gray;
}
</style>
</head>
<body>
<time></time>
<div id="container">Loading ...</div>
<script src="socket.io.js"></script>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
var rno = Math.floor((Math.random() * 10) + 1);
// create a new websocket
var socket = io.connect('http://localhost:8000/?profile_id=' + rno);
// on message received we print all the data inside the #container div
socket.on('notification', function(data) {
var usersList = "<dl>";
$.each(data.users, function(index, count) {
usersList += "<dt>" + count.c + "</dt>\n";
});
usersList += "</dl>";
$('#container').html(usersList);
$('time').html('Last Update:' + data.time);
$('sql').html('Last Update:' + data.sql);
});
</script>
</body>
</html>
答案 0 :(得分:0)
您的pollingLoop函数和查询的结构方式只能检索最后一个profile_id。原因如下: profile_id变量是一个全局变量,存在于服务器线程上。到目前为止你编程的方式,似乎你希望你的pollingLoop一次处理所有的套接字,但是在pollingLoop中,你使用全局变量profile_id来从数据库中提取信息。每当新用户连接“已连接”的用户时,事件触发,将profile_id更新为该用户。
无论哪种方式,您都必须修复您的profile_id,因为在全局设置中包含单个用户的唯一ID并不合理。如果您确实希望profile_id是基于会话的唯一ID,那么执行随机数会有点危险。我建议使用socket.io为每个套接字公开的socket.id。通过这种方式,您不必担心它是独一无二的,您不必将其传递,并且您不必自己存储它。 socket.id将在connectionsArray中可用,因为它包含所有套接字。因此,在pollingLoop中,您可以遍历ID以构建查询,并且在updateSockets中,您可以将结果配对回需要接收特定于该用户的数据的套接字。
关于连接事件中的评论还有一个注意事项: //仅当至少有一个用户连接时才启动循环 这个评论不准确,我认为应该说: //仅在没有其他用户连接的情况下启动循环
我希望能帮到你!