Socket.io fs.readFileSync用于同时进行许多连接

时间:2018-09-24 23:41:06

标签: node.js socket.io

这不是一个真正的问题,但是我想知道我所做的是否正确,因为它可以正常工作!

所以,让我们提一个问题,我正在监视多个接口(PPPoE客户端),以了解其流量,并从linux读取统计信息。

我正在使用npm软件包:express,socket.io和socket.io-stream。

客户:

var sessionsAccel = $('table.accel').DataTable([]);

sessionsAccel.on('preDraw', function() {
    $('.interfaceAccel').each(function(i) {
        var t = $(this).data();
        sockets['socket' + t.id].disconnect();
        delete speeds['tx_bytes' + t.id];
        delete speeds['rx_bytes' + t.id];
    });
})
.on('draw', function() {
    $('.interfaceAccel').each(function(i) {
        var t = $(this).data();
        sockets['socket' + t.id] = io.connect('http://172.16.101.2:3000/status', {
            query: 'interface=' + t.interface,
            'forceNew': true
        });
        sockets['socket' + t.id].on("connect", function() {
            ss(sockets['socket' + t.id]).on('sendStatus', function(stream, data) {
                if (typeof speeds['tx_bytes' + t.id] != 'undefined') {
                    var speedtx = (data.tx_bytes - speeds['tx_bytes' + t.id]) * 8 / 1000;
                    var speedrx = (data.rx_bytes - speeds['rx_bytes' + t.id]) * 8 / 1000;
                    if (speedtx > 1000) {
                        speedtx = speedtx / 1000;
                        speedtx = speedtx.toFixed(2);
                        speedtx_info = speedtx + ' Mbps';
                    } else {
                        speedtx = speedtx.toFixed(2);
                        speedtx_info = speedtx + ' kbps';
                    }

                    if (speedrx > 1000) {
                        speedrx = speedrx / 1000;
                        speedrx = speedrx.toFixed(2);
                        speedrx_info = speedrx + ' Mbps';
                    } else {
                        speedrx = speedrx.toFixed(2);
                        speedrx_info = speedrx + ' kbps';
                    }
                    $('.tx_' + t.id).html(speedtx_info);
                    $('.rx_' + t.id).html(speedrx_info);
                }
                speeds['tx_bytes' + t.id] = data.tx_bytes;
                speeds['rx_bytes' + t.id] = data.rx_bytes;
            });
        });
    });
})

服务器:

const app = require('express')();
const http = require('http').createServer(app);

const io = require('socket.io')(http);
const ss = require('socket.io-stream');
const path = require('path');
const fs = require('fs');

function getIntInfo(interface) {
    if(fs.existsSync('/sys/class/net/'+ interface +'/statistics/tx_bytes')) {
        var tx_bytes = fs.readFileSync('/sys/class/net/'+ interface +'/statistics/tx_bytes').toString();
        var rx_bytes = fs.readFileSync('/sys/class/net/'+ interface +'/statistics/rx_bytes').toString();
        var tx_packets = fs.readFileSync('/sys/class/net/'+ interface +'/statistics/tx_packets').toString();
        var rx_packets = fs.readFileSync('/sys/class/net/'+ interface +'/statistics/rx_packets').toString();
        return {tx_bytes : tx_bytes, rx_bytes : rx_bytes, tx_packets: tx_packets, rx_packets: rx_packets};
    }else
        return false;
}

io.of('/status').on('connection', function(socket) {
    var query = socket.handshake.query['interface'];
    var timer = setInterval(function() {
        var stream = ss.createStream();
        var info = getIntInfo(query);
        ss(socket).emit('sendStatus', stream, info);
    }, 1000);

    socket.on('disconnect', function(){
        socket.disconnect(true);
        //console.info('disconnected user (id=' + socket.id + ').');
    });
})

http.listen(3000, function(){
      console.log('listening on *:3000');
});

就是这样,Datatable中的每一行(即接口)都打开一个套接字连接并检索统计信息。

我的问题是,这会使许多读取这些文件的I / O弄乱我的服务器吗?

1 个答案:

答案 0 :(得分:0)

由于每个连接的客户端都在每秒执行一次此操作,因此似乎应该缓存该数据,这样就不必从磁盘读取数据,也可以在未更改保存状态时通过电线发送数据服务器负载和带宽使用率。但是,如何做到最好的细节取决于您尚未包括的特定应用程序的知识。

您至少可以这样使用异步I / O:

const util = require('util');
const fs = require('fs');
const readFile = util.promisify(fs.readFile);

function getIntInfo(interface) {
    function readInfo(name) {
        return readFile('/sys/class/net/'+ interface +'/statistics/' + name).then(data => data.toString());
    }
    return Promise.all(
        readFile('tx_bytes'),
        readFile('rx_bytes'),
        readFile('tx_packets'),
        readFile('rx_packets')
    ).then(([tx_bytes, rx_bytes, tx_packets, rx_packets]) => {
        return {tx_bytes, rx_bytes, tx_packets, rx_packets};
    }).catch(err => {
        console.log(err);
        return false;
    });
}

而且,您必须在客户端断开连接时停止间隔,并更改其调用getIntInfo()的方式:

io.of('/status').on('connection', function(socket) {
    var query = socket.handshake.query['interface'];
    var timer = setInterval(function() {
        getIntInfo(query).then(info => {
            var stream = ss.createStream();
            ss(socket).emit('sendStatus', stream, info);
        });
    }, 1000);

    socket.on('disconnect', function(){
        // stop the timer for this connection
        clearInterval(timer);
    });
});

现在,我想一想,只需一个间隔计时器来读取数据,然后将一组数据发送到已连接到{{ 1}}名称空间。无论有多少客户端,您都可以将文件读取速度从每个客户端每秒一次减少到每秒一次。