检测http.ServerResponse / Writable Stream是否具有空写入队列

时间:2012-11-08 22:19:42

标签: node.js

对于我的第一个node.js项目,我正在为某些mjpeg输出创建代理。现在,有些客户端无法像服务器那样快速地读取流,所以我正在丢帧以让它们赶上来。我目前正在使用drain对象的http.ServerResponse事件,或多或少如下,但因为drain被称为非常多,我想知道是否有更好的/更轻量级的方法(我在Writeable Stream docs中找不到)

httpServer.on('request',function(request,response){
    //skipped setting some headers etc.
    res.socket.on('drain', function(){
        res.drained = true;
        res.draincounter = 0;
    });
    //followed by some unconditional first write (set drained to false first)
    res.drained = false;
    res.write(someData);
};

现在,向客户端写帧的方式如下:

writeFrame = function(res,frame){
   if(res.drained){
       //nothing in queue, ready for new data

       //first set drained to false
       res.drained = false;
       //and feed it more data
       res.write(frame, 'binary');
   } else if(res.draincounter > maxDroppedFrames){
       //to many dropped frames in a row, disconnect
       res.end();
   } else {
       res.draincounter++;
   }
}

但是这会使用自定义属性,以及对排水事件的调用的很多(这可能没问题,但我的经验有限并不适合我)。简而言之,我的问题是:

有没有更有效的方法来检测Writable Stream的写缓冲区是空的?


编辑:关闭后,以节点0.10.18重新启动此项目后&休眠了一段时间,有一些非常错误,因为我不再得到drain事件(至少,不是如上所述)。现在,我检查res.socket.bufferSize是否高于某个标记以决定是否写入mjpeg框架,draincounter仍然有效。在我的情况下,提倡的pipe() from the stream docs in the comment不是解决方案,因为问题不是在客户端速度上写所有数据,而是丢弃数据当客户端的速度低于源流时。

任何人都可以告诉我在背压上处理丢弃数据的正确方法是什么(如果不是这样的话)?

1 个答案:

答案 0 :(得分:1)

我个人会直接检查res._writableState,但此时您正在深入了解可能会发生变化的节点源,但我怀疑这种情况将来会发生多大变化。

然而这就是事情成为艺术的时候。您可以查看许多不同的标志:https://github.com/joyent/node/blob/master/lib/_stream_writable.js#L40

如果要查看缓冲区的当前大小,可以查看res._writableState.length - https://github.com/joyent/node/blob/master/lib/_stream_writable.js#L79

只有在缓冲区为0时才会写入。

function writeFrame(res, frame) {
  if (res._writableState.length) {
    if (++res.droppedFrames > maxDroppedFrames) res.end()
  } else {
    res.write(frame)
  }
}

如果你只想在缓冲区低于高水位线时写(即它不需要排水),你可以检查res._writableState.needDrain - https://github.com/joyent/node/blob/master/lib/_stream_writable.js#L57

如果缓冲区低于高水位线,则只会写入:

function writeFrame(res, frame) {
  if (res._writableState.needDrain) {
    if (++res.droppedFrames > maxDroppedFrames) res.end()
  } else {
    res.write(frame)
  }
}

您可能感兴趣的还有其他标志。重点是你不必听任何drain事件或做任何内部状态标记。

旁注,您应该只关心maxDroppedFrames / second,而不是绝对总数。你也不应该使用binary编码,而只需编写原始缓冲区。

另外,这可能仅适用于节点0.10 +