[英]How to cleanly close FD on aborted http connection in node.js
我正在玩节点和(目前)只是尝试通过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 ServerRequest上的'close'事件并销毁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>
根据nodejs文档
http.ServerRequest
事件:'关闭'
表示在调用response.end()或能够刷新之前终止了下层连接。
就像'结束'一样,每个请求只发生一次此事件,之后不再发生“数据”事件。
注意:'close'可以在'end'之后触发,但反之亦然。
我认为end()会杀死管道的目标fh,这意味着如果首先触发结束,则有一个小窗口,管道在关闭后可能会尝试写入请求fh。 尝试将file.destroy()调用放在end()事件中。
我试图测试我的想法,但我不能得到错误,所以请告诉我,如果这对你有用。 我担心当我向其他用户打开我的应用程序时会遇到这个问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.