完成后关闭流

时间:2017-01-07 12:59:05

标签: node.js express stream video-streaming html5-video

我使用fs.createReadStream(path).pipe(res);使用Express流式传输HTML 5视频,如果我刷新页面太多次(成千上万次),最终会导致错误Error: EMFILE: too many open files。我假设我需要执行某种清理并关闭文件以防止这种情况,但我不确定需要做什么。

每次用户寻找客户端未加载的视频的一部分时,我都会创建一个读取流,这会在几分钟内发生此问题。任务管理器显示相同的文件打开数百次,因此似乎永远不会关闭。

流功能的相关部分:

fs.stat(path, function(err, stats) {
  var size = stats.size;
  var range = req.headers.range;

  if (range) {
    var parts = range.replace(/bytes=/, '').split('-');
    var start = parseInt(parts[0]);
    var end = parts[1] ? parseInt(parts[1]) : size - 1;
    var chunksize = (end - start) + 1;

    res.writeHead(206, {
      'Content-Range': 'bytes ' + start + '-' + end + '/' + size,
      'Accept-Ranges': 'bytes',
      'Content-Length': chunksize,
      'Content-Type': 'video/mp4'
    });

    fs.createReadStream(path, {start: start, end: end}).pipe(res);
  } else {
    res.writeHead(200, {
      'Content-Length': size,
      'Accept-Ranges': 'bytes',
      'Content-Type': 'video/mp4'
    });

    fs.createReadStream(path).pipe(res);
  }
});

2 个答案:

答案 0 :(得分:1)

事实证明,流只会被破坏而文件在到达结束时关闭 - 这很少发生,因为你必须加载整个文件而不寻求或关闭浏览器。

要解决此问题,您必须侦听响应的close事件并销毁该流:

res.on('close', function() {
  stream.destroy();
});

有时,即使将close函数放在请求函数的第一行,也永远不会调用它。我发现解决这个问题的一个相当hacky的方法是在创建流之前检查套接字是否被销毁:

if (req.socket.destroyed) {
  return;
}

固定流功能:

fs.stat(path, function(err, stats) {
  if (req.socket.destroyed) {
    return;
  }

  var stream;
  var size = stats.size;
  var range = req.headers.range;

  if (range) {
    var parts = range.replace(/bytes=/, '').split('-');
    var start = parseInt(parts[0]);
    var end = parts[1] ? parseInt(parts[1]) : size - 1;
    var chunksize = (end - start) + 1;

    res.writeHead(206, {
      'Content-Range': 'bytes ' + start + '-' + end + '/' + size,
      'Accept-Ranges': 'bytes',
      'Content-Length': chunksize,
      'Content-Type': 'video/mp4'
    });

    stream = fs.createReadStream(path, {start: start, end: end});
  } else {
    res.writeHead(200, {
      'Content-Length': size,
      'Accept-Ranges': 'bytes',
      'Content-Type': 'video/mp4'
    });

    stream = fs.createReadStream(path);
  }

  stream.pipe(res);

  res.on('close', function() {
    stream.destroy();
  });
});

答案 1 :(得分:0)

在Linux / Unix上EMFILE问题由ulimit解决。 我不确定在窗户上。 Google Windows ulimit EMFILE获得此Stack Overflow

https://stackoverflow.com/a/729204/683017

它说每个进程的2048个文件描述符是Windows的限制。这符合你的说法

  

“成千上万”

如果这个2048是一个坚定的限制,我不确定,(你将不得不四处寻找有关你的特定操作系统的更多信息)。

如果可能的话,可以考虑将负载重新平衡到更多进程或更多服务器。