消息块与可写流

时间:2015-09-21 20:41:49

标签: node.js stream

我使用的是nodejs 0.10和ws(websocket lib)。

我想实现自己的stream.Writable类来发送websocket消息 我的约束是:

  • 我必须将写入的数据分段为10KB的块,并在将它们发送到websocket之前为它们添加一个JSON标头
  • 最后一个块的JSON标头必须包含" last:true"

例如,如果我打电话:

myStream = new FoobarStream;
myStream.write(<a buffer of 7KB>);
myStream.end(<another buffer of 7KB>);

然后,我希望我的流能够在两条消息中发送这些数据:第一个将有其JSON标头,后跟10KB数据,第二个将有其JSON标头(包含&#34; last:true&#34;字段)后跟4KB数据。

这意味着我必须对数据发送进行临时调整,这意味着我必须找到一种方法来了解我何时编写消息的最后数据,因为这样&#34; last:true&#34;字段我必须写入JSON标题。

我不知道如何只继承stream.Writable的_write()方法。似乎我无法在_write()中知道是否已调用end(),因此我无法使用&#34; last: true&#34;来标记我的JSON标题。

这是否意味着我必须继承stream.Writable的end()方法?

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

可以从那里定义自己的end方法和句柄。但这意味着要重写原始end方法中的一些代码。

相反,您可以保留内部缓冲区并处理prefinishfinish事件中的最后一块。这是一个简单的例子:

function FoobarStream(options){
    Writable.call(this, options);


    this.on('prefinish', function(){
        if(this._buffer){
            //process the last chunk
            process.stdout.write('footer: '+ this._buffer+ "\n");
        }
    });
}

FoobarStream.prototype._write = function(chunk, encoding, cb){

    if(this._buffer){
        //process other chunks here
        process.stdout.write('header: ' + this._buffer+ "\n");
        this._buffer = chunk;
    }
    else
        this._buffer = chunk;
    cb();
}

myStream = new FoobarStream;
myStream.write('first line');
myStream.write('second line');
myStream.end('last line');

/*
outputs:
header: first line
header: second line
footer: last fine
*/

答案 1 :(得分:0)

您可以延迟写入接收器(基础WritableStream资源)直到process.nextTick,这将允许您检查finish(0.10中没有prefinish)事件是否已在写入结果之前在流上触发。以下是您可以运行的示例:

var Stream = require('stream');
var Util = require('util');

// Create a readable to test our FoobarStream out

var readable = new Stream.Readable();
var finished = false;

readable._read = function () {

    if (finished) {
        this.push(new Buffer('world'));
        return this.push(null);
    }

    this.push(new Buffer('hello '));
    finished = true;
};

// Create the FoobarStream

var FoobarStream = function (options, sink) {

    Stream.Writable.call(this, options);

    this.sink = sink;
    this.finished = false;

    this.on('finish', function () {
        this.finished = true;
    });
};

Util.inherits(FoobarStream, Stream.Writable);

FoobarStream.prototype.serialize = function (chunk) {

    var header = new Buffer(JSON.stringify({some: 'header', last: this.finished}));
    return Buffer.concat([header, chunk]);
};

FoobarStream.prototype._write = function (chunk, encoding, callback) {

    var self = this;

    process.nextTick(function () {
        self.sink.write(self.serialize(chunk));
    });

    callback();
}

readable.pipe(new FoobarStream(null, process.stdout));

控制台输出:

$ node index.js
{"my":"header","last":false}hello
{"my":"header","last":true}world