繁体   English   中英

如何在node.js中彻底关闭中断的http连接上的FD

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM