我正在使用" 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()
不起作用,因为我无法验证在第二台服务器上收到的数据。但如果我发表评论,我可以看到数据流传输到第二台服务器。
我的目标是关闭客户端服务器端的连接
答案 0 :(得分:0)
关闭套接字的主要问题似乎是你在尝试关闭套接字之前没有等待流写完。因此,因为写入都是异步的并且稍后完成,所以在写入数据之前,您试图关闭套接字。
另外,因为您将异步操作放在for
循环中,所以您还要并行运行所有操作,这可能不是您想要的,因为它使错误处理更加困难,并且服务器负载更加困难。 / p>
以下是我建议执行以下操作的代码:
streamFileFromS3()
,用于流式传输单个文件并返回一个将在完成后通知的承诺。await
循环中使用for
与streamFileFromS3()
序列化操作。您不必对它们进行序列化,但是您必须更改错误处理以确定如果一个错误而其他错误已经在运行并且您必须对并发问题更加小心,该怎么办streamFileFromS3()
。data['propertyName']
更改为data.propertyName
。您需要使用括号的唯一时间是属性名称是否包含Javascript标识符中不允许的字符,或者属性名称是否在变量中。否则,点符号是首选。所以,这里是代码:
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
是什么,因为它未在此处声明,当您并行执行所有操作时,它会在所有要求并发问题的连接之间共享。在我的序列化实现中,分享它可能是安全的,但它现在的方式困扰我,因为它是一个等待发生的并发问题。