如何在node.js中关闭没有更多数据发送的流?

4
我正在使用node.js,并通过打开/dev/tty文件从串口读取输入。我发送一个命令并读取命令的结果,当我读取和解析所有数据后,我想关闭流。我知道我已经完成数据的读取,并且已经到达了数据结束标记。但是,我发现一旦我关闭了流,我的程序并没有终止。
以下是一个示例,它展示了我所看到的情况,但是使用/dev/random来缓慢生成数据(假设您的系统没有太多活动)。 我发现,一旦设备在流关闭后生成数据,进程将终止。
var util = require('util'),
    PassThrough = require('stream').PassThrough,
    fs = require('fs');

// If the system is not doing enough to fill the entropy pool
// /dev/random will not return much data.  Feed the entropy pool with :
//  ssh <host> 'cat /dev/urandom' > /dev/urandom
var readStream = fs.createReadStream('/dev/random');
var pt = new PassThrough();

pt.on('data', function (data) {
    console.log(data)
    console.log('closing');
    readStream.close();  //expect the process to terminate immediately
});

readStream.pipe(pt);

更新:1

我回来了,针对这个问题,我有另一个示例,这个示例只是使用pty,并且可以在节点repl中轻松重现。在两个终端上登录,并使用您未在节点中运行的终端的pty以在下面的createReadStream调用中创建读取流。

var fs = require('fs');
var rs = fs.createReadStream('/dev/pts/1'); // a pty that is allocated in another terminal by my user
//wait just a second, don't copy and paste everything at once
process.exit(0);

此时,Node将会挂起而不会退出。这是在10.28版本中发生的。


也许这会有帮助?http://stackoverflow.com/questions/16399476/readstream-pipe-does-not-close - Matt Browne
我猜这并没有帮助?如果你错过了,那个问题的 OP 在问题底部放置了他们的解决方案(对我来说,一开始并不明显,我以为那只是更多问题)。 - Matt Browne
这是一种奇怪的行为。在 Mac Os (node v0.10.21) 中,OP 的代码立即退出... - Paul Mougel
可能是我漏看了,但那个问题是通过关闭与他们的数据库(mongoose)的连接来解决的,除了在代码中创建的流之外,我没有其他连接。 - ShaneH
3个回答

1

不要使用

readStream.close(), 

尝试使用。
readStream.pause().

但是,如果您正在使用最新版本的node,则可以将readstream与由isaacs创建的stream模块创建的对象结合起来,如下所示:

var Readable = require('stream').Readable;
var myReader = new Readable().wrap(readStream);

之后使用myReader代替readStream。

祝你好运!如果行得通,请告诉我。


当我这样做时,我得到了一个很好的堆栈跟踪。:) _stream_readable.js:730 throw new Error('现在无法切换到旧模式。'); - ShaneH
这与这个问题有关,该问题已在此次提交中得到解决。 - Paul Mougel
我根据你的错误更改了我的答案。实际上,我的答案只适用于旧版本的节点。对此我很抱歉。 - sam100rav

0

你正在关闭/dev/random流,但是你仍然有一个监听器监听着通过流的'data'事件,这将使应用程序一直运行,直到通过流被关闭。

我猜测读取流中可能存在一些缓冲数据,直到这些数据被刷新,通过流才会关闭。但这只是一个猜测。

为了获得所需的行为,您可以像这样删除通过流上的事件监听器:

pt.on('data', function (data) {
  console.log(data)
  console.log('closing');

  pt.removeAllListeners('data');
  readStream.close();
});

不,打印“closing”后该进程仍然保持原样。 - ShaneH
你在哪个平台上使用哪个版本的node运行这个代码?我已经在Windows 7上尝试了你的代码,使用了0.10.16版本,我发现代码有描述中的行为,但移除对pt监听器的监听后问题得到解决。我没有/dev/random,我从一个足够大的文件中读取数据,以64k块进行读取。使用我的更改后,进程在读取第一块后就返回了,而使用原始代码则需要等待第二块数据。 - mamapitufo
我在Linux平台上运行10.21版本。我期望你的测试能够正常工作,因为你的流将持续具有数据,而/dev/random则不然。可以打开/dev/random并附加一个on('data'),它会一直等待直到有数据发送。你的大文件发送第一个块时会触发数据事件,然后移除监听器并关闭流,但流仍然具有数据。 - ShaneH
我刚刚尝试了使用node 0.10.18从OSX的/dev/random读取数据,观察到了相同的行为:如果我保持监听器在pt上,则会收到2个“closing”消息,但是如果我在第一个“data”事件上删除监听器,则不会收到第二个消息。我不知道为什么你在Linux上无法使用它。 - mamapitufo
“data”监听器被添加到PassThrough流中,但是在ReadStream上调用了close()。如果我理解正确,您链接的代码中PassThrough流是“dest”,而不是“src”,因此它的“data”监听器不会被清除。 - mamapitufo
显示剩余2条评论

0

我实际上是管道到一个HTTP请求.. 所以对我来说,这是关于:

pt.on('close', (chunk) => {
  req.abort();
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接