对于我的第一个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或不是解决方案,因为问题不是在客户端速度上写所有数据,而是丢弃数据当客户端的速度低于源流时。
任何人都可以告诉我在背压上处理丢弃数据的正确方法是什么(如果不是这样的话)?
答案 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 +