在for循环中使用Node.js child_process.exec(),例如逐个ping IP地址

时间:2015-07-28 11:41:36

标签: javascript node.js

我想ping一个数组/ JSON中的每个IP地址以获得它们的可访问性。这是一个简单的场景:

var onlineCams = {};

for (var i = 0; i < ipList.cameras.length; i++) {
    var currentIp = ipList.cameras[i].ip;
    var currentIpStatus = "";
    var shellCmd = 'ping -c 1 ' + currentIp + ' | grep icmp* | grep bytes | wc -l';

    var child = exec(shellCmd, function (error, stdout, stderr) {
        if (stdout.toString().trim() == '1') 
            currentIpStatus = "Online";
        else 
            currentIpStatus = "Offline";

    onlineCams[currentIp] = currentIpStatus;
    });
}

示例输出:

// console.log(ipList.cameras);
[ { id: 0, ip: '192.168.79.139' },
  { id: 1, ip: '192.168.79.16' } ]

// console.log(onlineCams);
{ '192.168.79.16': 'Online' }

onlineCams中只有一个IP地址应该有两个。出于某种原因,跳过了.139,我猜它是因为exec线程在.139的结果被返回之前覆盖了自己。这有什么变通方法吗?

1 个答案:

答案 0 :(得分:2)

您正在尝试使用同步循环来管理多个异步操作。 您可以使用exec_sync或重构代码。

一个不错的解决方案是使用Promises,而node.js bluebird是我首选的库。

然后你可以写这样的东西(也许是非常好的!):

var Promise = require('bluebird');
var exec = require('child_process').exec;
var ipList = {
    cameras: [{
        ip: 'yahoo.com'
    }, {
        ip:'google.com'
    },{
        ip: 'fake.fake'
    }]
};
var onlineCams = {};
var promises = [];
function checkIp(ip) {
    return new Promise(function (resolve, reject) {
        var shellCmd = 'ping -c 1 ' + ip + ' | grep icmp* | grep bytes | wc -l';
        exec(shellCmd, function (err, stdout, stderr) {
            if (err) {
                reject(err);
            }
            var result = {};
            result[ip] = stdout.toString().trim() === '1' ? 'Online' : 'Offline';
            resolve(result);
        });
    });
}

for (var i = 0; i < ipList.cameras.length; i++) {
    promises.push(checkIp(ipList.cameras[i].ip));
}

Promise.all(promises).then(function (results) {
    console.log(results);
});