NodeJS流分裂

时间:2016-12-26 14:54:12

标签: node.js stream pipe streamwriter node.js-stream

我有来自分叉进程的无限数据流。我希望这个流由模块处理,有时我想复制来自此流的数据以由不同的模块处理(例如,监视数据流,但如果发生任何有趣的事情,我想将下n个字节记录到文件中进一步调查)。

让我们假设以下情况:

  1. 我启动程序并开始使用可读流
  2. 2秒后我想通过不同的流阅读器处理相同的数据1秒
  3. 一旦时间到了,我想关闭第二个消费者,但最初的消费者必须保持不变。
  4. 以下是此代码段:

    var stream = process.stdout;
    
    stream.pipe(detector); // Using the first consumer
    
    function startAnotherConsumer() {
        stream2 = new PassThrough();
        stream.pipe(stream2);
    
        // use stream2 somewhere else
    }
    
    function stopAnotherConsumer() {
        stream.unpipe(stream2);
    }
    

    我的问题是,删除stream2并不会让它关闭。如果我在stream.end()命令后调用unpipe,那么它会因错误而崩溃:

    events.js:160
          throw er; // Unhandled 'error' event
          ^
    
    Error: write after end
        at writeAfterEnd (_stream_writable.js:192:12)
        at PassThrough.Writable.write (_stream_writable.js:243:5)
        at Socket.ondata (_stream_readable.js:555:20)
        at emitOne (events.js:101:20)
        at Socket.emit (events.js:188:7)
        at readableAddChunk (_stream_readable.js:176:18)
        at Socket.Readable.push (_stream_readable.js:134:10)
        at Pipe.onread (net.js:548:20)
    

    我甚至尝试暂停源流以帮助缓冲区从第二个流中刷新,但它也不起作用:

    function stopAnotherConsumer() {
        stream.pause();
        stream2.once('unpipe', function () {
            stream.resume();
            stream2.end();
        });
        stream.unpipe(stream2);
    }
    

    与此前相同的错误(写完后)。

    如何解决问题?我的初衷是从一个点复制流数据,然后在一段时间后关闭第二个流。

      

    注意:我尝试使用this answer使其正常工作。

1 个答案:

答案 0 :(得分:1)

由于没有答案,我发布了我的(拼凑)解决方案。如果有人有更好的,请不要阻止它。

新流:

const Writable = require('stream').Writable;
const Transform = require('stream').Transform;

class DuplicatorStream extends Transform {
    constructor(options) {
        super(options);

        this.otherStream = null;
    }

    attachStream(stream) {
        if (!stream instanceof Writable) {
            throw new Error('DuplicatorStream argument is not a writeable stream!');
        }

        if (this.otherStream) {
            throw new Error('A stream is already attached!');
        }

        this.otherStream = stream;
        this.emit('attach', stream);
    }

    detachStream() {
        if (!this.otherStream) {
            throw new Error('No stream to detach!');
        }

        let stream = this.otherStream;
        this.otherStream = null;
        this.emit('detach', stream);
    }

    _transform(chunk, encoding, callback) {
        if (this.otherStream) {
            this.otherStream.write(chunk);
        }

        callback(null, chunk);
    }
}

module.exports = DuplicatorStream;

用法:

var stream = process.stdout;
var stream2;

duplicatorStream = new DuplicatorStream();
stream.pipe(duplicatorStream);   // Inserting my duplicator stream in the chain
duplicatorStream.pipe(detector); // Using the first consumer

function startAnotherConsumer() {
    stream2 = new stream.PassThrough();
    duplicatorStream.attachStream(stream2);

    // use stream2 somewhere else
}

function stopAnotherConsumer() {
    duplicatorStream.once('detach', function () {
        stream2.end();
    });
    duplicatorStream.detachStream();
}