我正在玩节点和(目前)只是尝试通过HTTP从文件系统流式传输一些文件。
我的OS X Lion机器上的Apache Bench(ab)应用程序出现问题,似乎过早地中断了连接。这似乎突出了我的node.js应用程序的问题,如果连接中止,它会泄漏文件句柄。
我把它简化为一个简单的node.js测试用例。当我启动它并对它运行'ab'时,由于打开的文件句柄太多,我最终会得到一个EMFILE异常:
// app.js
var count = 0;
require('http').createServer(function(req,res){
console.log('request ' + ++count);
res.writeHead(200);
require('fs').createReadStream(
'/Users/tom/files/8339cdf73594d8f0aab87da123e9e0380723b471'
).pipe(res);
}).listen('3000');
$ node app.js
request 1
...
request 317
request 318
request 319
stream.js:105
throw er; // Unhandled stream error in pipe.
^
Error: EMFILE, too many open files '/Users/tom/files/8339cdf73594d8f0aab87da123e9e0380723b471'
我假设发生的事情是HTTP连接被中止但节点的.pipe()机制不知道停止从可读流中读取并关闭FD,所以我试图在HTTP上处理'close'事件ServerRequest并销毁FD,但是当我得到一个错误的FD错误(EBADF)时,似乎仍在读取它:
// app.js
var count = 0;
require('http').createServer(function(req,res){
console.log('request ' + ++count);
res.writeHead(200);
var file = require('fs').createReadStream(
'/Users/tom/dev/cloudstore2/files/8339cdf73594d8f0aab87da123e9e0380723b471'
);
req.on('close', function(){
console.log('request received close - destroying read FD');
file.destroy();
});
file.pipe(res);
}).listen('3000');
$ node app.js
...
request 112
request 113
request received close - destroying read FD
request received close - destroying read FD
request received close - destroying read FD
request received close - destroying read FD
request received close - destroying read FD
request received close - destroying read FD
request received close - destroying read FD
events.js:48
throw arguments[1]; // Unhandled 'error' event
^
Error: EBADF, bad file descriptor
是否有'正确'的方法来处理这些中止的HTTP连接并关闭我关联的fs读取流,或者我在node.js'.pipe()处理中看到了错误?
更新 通过在我的文件阅读器上捕获“错误”事件,我可以避免应用程序在此过程中死亡,但这是正确的方法吗?我觉得我错过了一些方法来避免首先出现错误的FD错误。
<snip>
var file = require('fs').createReadStream(
'/Users/tom/dev/cloudstore2/files/8339cdf73594d8f0aab87da123e9e0380723b471'
);
file.on('error', function(err){
console.log('error handled in file reader: ' + err);
});
req.on('close', function(){
console.log('request received close - destroying read FD');
file.destroy();
});
file.pipe(res);
</snip>
答案 0 :(得分:2)
根据nodejs文档
<强> http.ServerRequest 强>
事件:'关闭'
表示之前终止了下层连接 response.end()被调用或能够刷新。
就像'结束'一样,每个请求只发生一次此事件,而不再发生 “数据”事件将在事后发生。
注意:'close'可以在'end'之后触发,但反之亦然。
我认为end()会杀死管道的目标fh,这意味着如果首先触发结束,则有一个小窗口,管道在关闭后可能会尝试写入请求fh。尝试将file.destroy()调用放在end()事件中。
我试图测试我的想法,但我无法得到错误,所以请告诉我,如果这对您有用。我担心当我向其他用户打开我的应用程序时会遇到这个问题。