代码之家  ›  专栏  ›  技术社区  ›  user2248702

完成后关闭流

  •  1
  • user2248702  · 技术社区  · 9 年前

    我正在使用Express流式传输HTML 5视频 fs.createReadStream(path).pipe(res); 这最终导致了错误 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 回复  |  直到 9 年前
        1
  •  1
  •   user2248702    9 年前

    事实证明,只有在到达结束时,流才会被破坏,文件才会被关闭,这种情况很少发生,因为您必须在不查找或关闭浏览器的情况下加载整个文件。

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

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

    有时,即使将close处理程序放在请求函数的第一行,也不会调用它。我发现了一种相当有技巧的方法来解决这个问题,就是在创建流之前检查套接字是否被破坏:

    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();
      });
    });
    
        2
  •  0
  •   Community Mohan Dere    9 年前

    在Linux/Unix上 EMFILE 问题通过以下方式解决: ulimit . 我不确定在windows上。 谷歌 Windows ulimit EMFILE 获取此堆栈溢出

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

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

    “成千上万”

    如果2048年是一个固定的限制,我不确定它是(你将不得不四处搜索以了解更多关于你的特定操作系统的信息)。

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