2016-03-04 10 views
2

我有一個tcp服務器,我將所有客戶端數據存儲在客戶端陣列。 所以當有人斷開我只是拼接他們。拼接後數組不會改變它的數據。範圍問題?

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

我有一個顯示所有在線用戶的函數。它只是從該客戶端陣列獲取數據並將其顯示給我。

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

頂部所以現在宣佈,當客戶端斷開I接續他和接收這些日誌。

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 

因此,它只有1個用戶在客戶端陣列。然後我用我的秀在線用戶功能,它給我這樣的日誌

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

它顯示,有2個用戶。怎麼可能? 是範圍問題嗎?或者它可能是什麼?謝謝你的回覆。

來源。 我想我做的插座有問題。這段代碼的工作,但它運行的時間越長,我在客戶端陣列中仍然是幻影客戶端。

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; 
} 
+0

如何通過tcp檢索關於有多少用戶連接的信息?也許,當您嘗試檢索信息時,這是您的「額外」連接? :) –

+0

啊不,我創建http服務器,並從它發出請求ShowOnlineUsers。這是在其他端口,它不會連接到tcp服務器100% – SLI

+0

它不可能告訴發生了什麼,如果你沒有發佈你使用它的所有代碼... – highstakes

回答

1

這是你的罪魁禍首:

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

我看到你使用這個函數來獲取供以後使用數組中的插座指數(由物業ID引用)。

這是問題所在。

試想一下,你的應用程序事件的順序:

在這一點上,你有2個連接。

  1. 現在接收新的連接 你只是把第3插座到客戶端陣列 tempSocket現擁有2

  2. 應用程序調用的API的ID來獲得一個關鍵

  3. 的現有的套接字接收到斷開連接事件 該應用程序從客戶端陣列中刪除現有的套接字,並且您只能使用2個套接字。它有兩個,因爲我們已經添加了新的插座#1

  4. 子彈#2中的api調用返回了密鑰 現在調用updateStocket(tempSocket)來更新它。 問題是tempSocket.id指向索引2,但在數組中只有2個元素。

我sugguestion:

我。將客戶端陣列更改爲對象集合 ii。當你得到一個新的套接字連接時,使用像UUID.js這樣的庫來獲得一個唯一的十六進制,並將它分配給新的套接字屬性 iii。添加新的插座如果你決定作出上述改變使用十六進制ID

給客戶對象,你就必須更新你的迭代方法。我建議使用lodash來幫助你迭代你的數組和對象。這真的很方便。否則,你必須得到對象鍵並遍歷它們。

祝你好運。

+0

謝謝你的回覆,我會盡力做到這一點! – SLI

+0

現在所有的工作都很好 – SLI