流数据后如何断开套接字?

时间:2018-03-11 19:12:03

标签: node.js socket.io

我正在使用" socket.io-client"和" socket.io stream"发出请求,然后流式传输一些数据。我有以下代码来处理这个逻辑

客户端服务器逻辑

router.get('/writeData', function(req, res) {
    var io = req.app.get('socketio');
    var nameNodeSocket = io.connect(NAMENODE_ADDRESS, { reconnect: true });

    var nameNodeData = {};

    async.waterfall([
        checkForDataNodes,
        readFileFromS3
    ], function(err, result) {
        if (err !== null) {
            res.json(err);
        }else{
            res.json("Finished Writing to DN's");
        }
    });

    function checkForDataNodes(cb) {
        nameNodeSocket.on('nameNodeData', function(data) {
            nameNodeData = data;
            console.log(nameNodeData);
            cb(null, nameNodeData);
        });
        if (nameNodeData.numDataNodes === 0) {
            cb("No datanodes found");
        }
    }

    function readFileFromS3(nameNodeData, cb) {
        for (var i in nameNodeData['blockToDataNodes']) {
            var IP = nameNodeData['blockToDataNodes'][i]['ipValue'];
            var dataNodeSocket = io.connect('http://'+ IP +":5000");
            var ss = require("socket.io-stream");
            var stream = ss.createStream();

            var byteStartRange = nameNodeData['blockToDataNodes'][i]['byteStart'];
            var byteStopRange = nameNodeData['blockToDataNodes'][i]['byteStop'];
            paramsWithRange['Range'] = "bytes=" + byteStartRange.toString() + "-" + byteStopRange.toString();

            //var file = require('fs').createWriteStream('testFile' + i + '.txt');
            var getFileName = nameNodeData['blockToDataNodes'][i]['key'].split('/');
            var fileData = {
                'mainFile': paramsWithRange['Key'].split('/')[1],
                'blockName': getFileName[1]
            };
            ss(dataNodeSocket).emit('sendData', stream, fileData);
            s3.getObject(paramsWithRange).createReadStream().pipe(stream);
            //dataNodeSocket.disconnect();
        }
        cb(null);
    }
}); 

服务器逻辑(获取数据)

var dataNodeIO = require('socket.io')(server);
var ss = require("socket.io-stream");
dataNodeIO.on('connection', function(socket) {
    console.log("Succesfully connected!");
    ss(socket).on('sendData', function(stream, data) {
        var IP = data['ipValue'];
        var blockName = data['blockName'];
        var mainFile = data['mainFile'];
        dataNode.makeDir(mainFile);
        dataNode.addToReport(mainFile, blockName);
        stream.pipe(fs.createWriteStream(mainFile + '/' + blockName));
    });
});

如何正确断开function readFileFromS3中的连接。我注意到最后使用dataNodeSocket.disconnect()不起作用,因为我无法验证在第二台服务器上收到的数据。但如果我发表评论,我可以看到数据流传输到第二台服务器。

我的目标是关闭客户端服务器端的连接

1 个答案:

答案 0 :(得分:0)

关闭套接字的主要问题似乎是你在尝试关闭套接字之前没有等待流写完。因此,因为写入都是异步的并且稍后完成,所以在写入数据之前,您试图关闭套接字。

另外,因为您将异步操作放在for循环中,所以您还要并行运行所有操作,这可能不是您想要的,因为它使错误处理更加困难,并且服务器负载更加困难。 / p>

以下是我建议执行以下操作的代码:

  1. 创建一个功能streamFileFromS3(),用于流式传输单个文件并返回一个将在完成后通知的承诺。
  2. await循环中使用forstreamFileFromS3()序列化操作。您不必对它们进行序列化,但是您必须更改错误处理以确定如果一个错误而其他错误已经在运行并且您必须对并发问题更加小心,该怎么办
  3. 使用try / catch捕获streamFileFromS3()
  4. 中的任何错误
  5. 在流上添加错误处理。
  6. 将所有data['propertyName']更改为data.propertyName。您需要使用括号的唯一时间是属性名称是否包含Javascript标识符中不允许的字符,或者属性名称是否在变量中。否则,点符号是首选。
  7. 为socket.io连接添加socket.io连接错误处理逻辑。
  8. 当处理请求时出现错误
  9. ,将返回状态设置为500

    所以,这里是代码:

    const ss = require("socket.io-stream");
    
    router.get('/writeData', function(req, res) {
        const io = req.app.get('socketio');
    
        function streamFileFromS3(ip, data) {
            return new Promise((resolve, reject) => {
                const dataNodeSocket = io.connect(`http://${ip}:5000`);
                dataNodeSocket.on('connect_error', reject);
                dataNodeSocket.on('connect_timeout', () {
                    reject(new Error(`timeout connecting to http://${ip}:5000`));
                });
                dataNodeSocket.on('connection', () => {
                    // dataNodeSocket connected now
                    const stream = ss.createStream().on('error', reject);
                    paramsWithRange.Range = `bytes=${data.byteStart}-${data.byteStop}`;
    
                    const filename = data.key.split('/')[1];
                    const fileData = {
                        'mainFile': paramsWithRange.Key.split('/')[1],
                        'blockName': filename
                    };
                    ss(dataNodeSocket).emit('sendData', stream, fileData);
                    // get S3 data and pipe it to the socket.io stream
                    s3.getObject(paramsWithRange).createReadStream().on('error', reject).pipe(stream);
                    stream.on('close', () => {
                        dataNodeSocket.disconnect();
                        resolve();
                    });
                });
            });
        }
    
        function connectError(msg) {
            res.status(500).send(`Error connecting to ${NAMENODE_ADDRESS}`);
        }
    
        const nameNodeSocket = io.connect(NAMENODE_ADDRESS, { reconnect: true });
        nameNodeSocket.on('connect_error', connectError).on('connect_timeout', connectError);
        nameNodeSocket.on('nameNodeData', async (nameNodeData) => {
            try {
                for (let item of nameNodeData.blockToDataNodes) {
                    await streamFileFromS3(item.ipValue, item);
                }
                res.json("Finished Writing to DN's");
            } catch(e) {
                res.status(500).json(e);
            }
        });
    }); 
    

    其他说明:

    我不知道paramsWithRange是什么,因为它未在此处声明,当您并行执行所有操作时,它会在所有要求并发问题的连接之间共享。在我的序列化实现中,分享它可能是安全的,但它现在的方式困扰我,因为它是一个等待发生的并发问题。