arrays在拼接后不会改变它的数据。 范围问题?

我有一个tcp服务器,我将所有客户端数据存储在客户端arrays。 所以当有人断开我只是拼接他们。

clients.splice(clients.indexOf(socket), 1); 

我有一个function,显示所有在线用户。 这只是从该客户端arrays获取数据,并显示给我。

 function showOnline(){ console.log("Show user list"); console.log("clients.length = " + clients.length); } 

客户端数组在app.js文件的顶部宣布

 var clients = []; <- here it is var http = require('http'); var net = require('net'); 

所以现在当客户端断开我拼接他,并收到这样的日志。

 console.log("clients.indexOf(socket) = " + clients.indexOf(socket)); console.log("clients.length = " + clients.length); clients.splice(clients.indexOf(socket), 1); console.log("after splice clients.length = " + clients.length); LOG 2016-03-04 22:06:33 clients.length = 2 after splice clients.length = 1 

所以在客户端arrays中只有一个用户。 然后我用我的秀在线用户function,它给我这样的日志

 LOG 2016-03-04 22:06:41 - Show user list clients.length = 2 

这表明有2个用户。 怎么可能? 这是范围问题吗? 或者它可能是什么? 谢谢你的回复。

资源。 我想我的套接字做错了。 这段代码的工作,但运行时间越长,我在客户端arrays仍然是幻影客户端。

 var clients = []; var packetReg = /(ART\D\d{4}(.*?)\DAND)/g; var serverUrl = "http://localhost:4000/" // Exit packet var p = { exit: true }; var ePacket = 'ART|' + randomNumber(1000, 9000) + JSON.stringify(p) + '|AND'; var fs = require('fs'); var http = require('http'); var https = require('https'); var net = require('net'); var url = require('url'); http.createServer(function (req, res) { var queryData = url.parse(req.url, true).query; res.writeHead(200, {"Content-Type": "text/html; charset=utf-8"}); if (queryData.clean) { kick(); } else if (queryData.expel) { kick(); } else if (queryData.list) { showUserList(); } else { res.writeHead(302, {'Location': 'https://localhost'}); res.end(); } function kick(all){ if (queryData.expel){ LOG("Expel user " + queryData.expel + " cmd"); } else LOG("Kick all cmd"); clients.forEach(function (client) { if (queryData.expel){ if (client.key != queryData.expel) return; } client.write(ePacket); }); if (queryData.expel){ res.end("done"); } else { cleanOnline(); res.end("disconnected - " + clients.length); } } function showUserList(){ LOG("Show user list"); var temp = 'Clients: ' + clients.length + generateButton('?clean=1', 'Kick all') + '<br>'; clients.forEach(function (client) { temp += 'User: ' + client.name + ' Key: ' + client.key + generateButton('?expel=' + client.key, 'Kick') + '<br>'; }); console.log("clients.length = " + clients.length); res.end(temp); } function generateButton(link, text){ return ' <a href="' + serverUrl + link + '" target="_blank" onClick="window.location.reload()"><button>' + text + '</button></a> '; } }).listen(4000, function(){ console.log('listening http on port 4000'); }); var tcpSocket = net.createServer(); tcpSocket.on('connection', function (socket) { socket.setNoDelay(true); socket.banned = false; socket.isAdmin = false; socket.isModerator = false; socket.name = 'newUser' socket.key = '' socket.armbuf = ''; clients.push(socket); LOG("New connection #" + clients.length); // Exit packet that close opened software socket.on('doExit', function () { LOG("Send exit packet"); var p = { exit: true }; socket.write('ART|' + randomNumber(1000, 9000) + JSON.stringify(p) + '|AND'); socket.destroy(); }); // Init packet socket.on('init', function (newData) { LOG("Init packet"); //newData.data = packet with key from my program //I find out if users start my program few times then they will be added few times at clients array. //So i want to prevent that with that function. It finds sockets with same key and just disconnect them except for the last socket. // FindAndCleanDuplicateSockets(newData.data, socket); var tempSocket = findSocket(socket); tempSocket.socket.key = newData.data; LOG("Send request to localhost about key " + tempSocket.socket.key); https.get('https://localhost/tgo/api/?apiRequest&key=' + tempSocket.socket.key, (res) => { var initData = ''; res.on('data', function (chunk) { initData += chunk; }); res.on('end', function() { LOG("Receive answer from localhost - " + initData.toString()); var a = JSON.parse(initData.toString()); if (a.data = "OK"){ tempSocket.socket.name = a.name; tempSocket.socket.banned = !Boolean(a.chatBan); if (a.type == "admin") tempSocket.socket.isAdmin = true; else if (a.type == "moderator") tempSocket.socket.isModerator = true; updateSocket(tempSocket); broadcast(packetMaker(tempSocket.socket.name, 'start'), socket); } else socket.emit('doExit'); }); }).on('error', (e) => { socket.emit('doExit'); }); }); //When user send ping packet socket.on('ping', function (newData) { //LOG("Ping packet"); var p = { currentTime: currentTime() }; socket.write('ART|' + randomNumber(1000, 9000) + JSON.stringify(p) + '|AND'); }); // When user change his name socket.on('newName', function (newData) { LOG("User change name from " + socket.name + " to " + newData.data); var tempSocket = findSocket(socket); tempSocket.socket.name = newData.data; updateSocket(tempSocket); }); //When user send new message packet socket.on('newMsg', function (newData) { LOG("newMsg packet"); var tempSocket = findSocket(socket); if (tempSocket.socket.banned) { LOG('User ' + tempSocket.socket.key + ' chat is banned'); return; } var type = 'msg'; if (tempSocket.socket.isAdmin) type = 'admin'; else if (tempSocket.socket.isModerator) type = 'moderator'; broadcast(packetMaker(tempSocket.socket.name, type, String(newData.data)), socket); }); // Handle incoming messages from clients. socket.on('data', function (newData) { var d = String(newData); //LOG('Received data: ' + d); // I find that socket bacause i use buffer to store data. If i won't do that it will give me "is not defined" error var tempSocket = findSocket(socket); tempSocket.socket.armbuf += d; var dataArray = tempSocket.socket.armbuf.match(packetReg); if (dataArray != null && dataArray.length > 0){ dataArray.forEach(function (match) { tempSocket.socket.armbuf = tempSocket.socket.armbuf.replace(match, ""); if (match.startsWith('ART|') && match.endsWith('|AND')) { var j = JSON.parse(cleanPacket(match)); switch (j.type) { case 'init': socket.emit('init', j); break; case 'ping': socket.emit('ping', j); break; case 'newName': socket.emit('newName', j); break; case 'newMsg': socket.emit('newMsg', j); break; default: break; } } else console.log('Bad packet: ' + match); //LOG("armbuf.length = " + tempSocket.socket.armbuf.length); }); } updateSocket(tempSocket); }); socket.on('error',function(error) { socket.end(); }); socket.on('close',function() { var tempSocket = findSocket(socket); LOG("Send logout notification to localhost - " + tempSocket.socket.key); // Send info to api that user logout https.get('https://localhost/tgo/api/?logout&key=' + tempSocket.socket.key); // Broadcast data to all users that client is logout broadcast(packetMaker(tempSocket.socket.name, 'exit'), socket); console.log("clients.indexOf(socket) = " + clients.indexOf(socket)); console.log("clients.length = " + clients.length); // Delete user from clients array clients.splice(clients.indexOf(socket), 1); console.log("after splice clients.length = " + clients.length); LOG("Close from API - " + tempSocket.socket.key); socket.destroy(); }); function cleanPacket(packet){ packet = packet.replace("ART|", ""); packet = packet.replace("|AND", ""); return packet.substring(4); } function findSocket(socket){ var socketData = { 'id': clients.indexOf(socket), 'socket': clients[clients.indexOf(socket)] }; return socketData; } function FindAndCleanDuplicateSockets(key, exclude){ clients.forEach(function (client) { if (client == exclude && client.key != key) return; LOG("User already exist in array. Delete old socket"); client.emit('doExit'); }); } function findAllSocketsByKey(key, excludeSocket){ var sockets = []; clients.forEach(function (client) { if (client == excludeSocket && client.key != key) return; sockets.push(client); }); return sockets; } function updateSocket(tempSocket){ clients[tempSocket.id] = tempSocket.socket; } // Send a message to all clients function broadcast(message, sender) { if (clients.length <= 0) return; LOG('broadcast ' + message); clients.forEach(function (client) { // Don't want to send it to sender if (client === sender) return; client.write(message); }); } function packetMaker(userName, packetType, userMsg){ var p = { currentTime: currentTime(), chat: { user: userName, type: packetType } }; if (typeof userMsg != 'undefined') p['chat']['msg'] = userMsg; return 'ART|' + randomNumber(1000, 9000) + JSON.stringify(p) + '|AND'; } }); tcpSocket.listen(5000, function(){ console.log('listening tcpSocket on port 5000'); cleanOnline(); }); function cleanOnline(){ console.log('Clean DB online'); //https.get('https://localhost/tgo/api/?apiCleanOnline'); } function LOG(data){ console.log(currentTime() + " - " + data); } function randomNumber(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } function currentTime() { var date = new Date(); var hour = date.getHours(); hour = (hour < 10 ? "0" : "") + hour; var min = date.getMinutes(); min = (min < 10 ? "0" : "") + min; var sec = date.getSeconds(); sec = (sec < 10 ? "0" : "") + sec; var year = date.getFullYear(); var month = date.getMonth() + 1; month = (month < 10 ? "0" : "") + month; var day = date.getDate(); day = (day < 10 ? "0" : "") + day; return year + "-" + month + "-" + day + " " + hour + ":" + min + ":" + sec; } 

这是你的罪魁祸首:

 function findSocket(socket){ var socketData = { 'id': clients.indexOf(socket), 'socket': clients[clients.indexOf(socket)] }; return socketData; } 

我看到你使用这个函数来获取数组中的套接字索引(由属性ID引用)供以后使用。

这是问题。

想象一下你的应用程序中的这一系列事件:

此时你有2个连接。

  1. 现在接收新的连接你刚把第三个套接字插入到客户端数组tempSocket现在有一个2的ID

  2. 该应用程序调用一个API来获得一个关键

  3. 现有的套接字接收到断开连接事件该应用程序从客户端arrays中删除现有的套接字,并且您下降到2个套接字。 它有两个,因为我们已经在第一个子弹中添加了新的套接字

  4. 子弹#2中的api调用返回键现在你调用updateStocket(tempSocket)来更新它。 问题是tempSocket.id指向索引2,但在数组中只有2个元素。

我的build议是:

一世。 将客户端数组更改为对象集合ii。 当你得到一个新的套接字连接时,使用像UUID.js这样的库来获得一个唯一的hex,并将它分配给新的套接字属性iii。 使用hexID将新的套接字添加到客户端对象

如果您决定进行上述更改,则必须更新迭代方法。 我build议使用lodash来帮助你迭代你的数组和对象。 这真的很方便。 否则,你必须得到对象键并遍历它们。

祝你好运。