Nodejs 求大神揭开谜底!unhandled exception:Error: accept EMFILE
Nodejs 求大神揭开谜底!unhandled exception:Error: accept EMFILE
node.js使用http.request请求别的服务器数据时,有时会报错err:socket hands up ! 当socket hands up 过多时又会报错: unhandled exception:Error: accept EMFILE at errnoException (net.js:769:11) at TCP.onconnection (net.js:1017:24) 直接导致程序必须重启。 求解!设置请求超时时间的时候,当请求超时时候调用abort()或者destroy()释放还是会报错err:socket hands up ! socket hands up是什么原因? 具体代码如下: function(req, res) {
transtr='*******';
var options = {
host : 'xxxxxxxxxxxx',
port : 80,
path : '/ajax/requestHead.do',
data : transtr,
method : 'POST',
headers : {
'Content-Type' : 'application/x-www-form-urlencoded',
'Content-Length' : transtr.length,
'Connection':'close'
}
};
console.log(transtr+'----------------------------------------');
var request_timer = null, serareq = null;
var serareq = http.request(options, function(serares) {
var heads = serares.headers;
serares.setEncoding('utf8');
clearTimeout(request_timer);
// 等待响应60秒超时
var response_timer = setTimeout(function() {
serares.destroy();
console.log('Response Timeout.');
}, 60000);
console.log("Got response: " + res.statusCode);
var resData= '';
serares.on('data', function (respData) {
resData += respData;
});
serares.on('end', function () {
clearTimeout(response_timer);
log.logger.info('=======rData============================')
res.send(resData);
});
});
serareq.on("timeout", function() {
//res.send('');
log.logger.info("timeout received");
if (serareq.serares) {
serareq.serares.emit("abort");
}
serareq.abort();
});
//设置请求超时时间5秒
request_timer = setTimeout(function() {
//serareq.abort();
serareq.emit("timeout",{message:'have been timeout...'});
log.logger.info('=====Request Timeout.=================');
}, 5000);
log.logger.info("Send packageData!!!!!!!!!!!!!!!!");
// write data to request body
serareq.write(transtr);
serareq.end();
}
Node.js 中 unhandled exception: Error: accept EMFILE
问题解析
问题描述
当你在 Node.js 中频繁发起 HTTP 请求时,可能会遇到 unhandled exception: Error: accept EMFILE
错误。这通常是因为操作系统限制了每个进程可以打开的文件描述符(file descriptors)数量。当你的 Node.js 应用程序尝试创建超过系统允许的最大文件描述符数时,就会抛出这个错误。
原因分析
- 文件描述符:每个打开的文件、网络连接等都会占用一个文件描述符。在 Node.js 中,HTTP 请求也会占用文件描述符。
- 系统限制:不同的操作系统有不同的默认文件描述符限制。例如,在 Linux 上,默认值通常是 1024。
解决方案
要解决这个问题,可以通过以下几种方式:
-
增加文件描述符限制
- 对于 Linux 系统,你可以通过修改
/etc/security/limits.conf
文件来增加每个用户的文件描述符限制。
* soft nofile 4096 * hard nofile 4096
- 对于 Linux 系统,你可以通过修改
-
优化代码逻辑
- 确保在完成请求后正确关闭或销毁 HTTP 请求对象。
- 使用连接池来管理并发请求,避免同时发起过多的请求。
-
调整超时处理
- 在发起请求时设置合理的超时时间,并确保在请求超时时正确地终止请求。
示例代码改进
以下是改进后的代码示例,展示了如何更好地管理请求并防止出现 EMFILE
错误。
const http = require('http');
function(req, res) {
const transtr = '*******';
const options = {
host: 'xxxxxxxxxxxx',
port: 80,
path: '/ajax/requestHead.do',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(transtr),
'Connection': 'close'
}
};
console.log(transtr + '----------------------------------------');
let request_timer = null;
let serareq = null;
serareq = http.request(options, function (serares) {
const heads = serares.headers;
serares.setEncoding('utf8');
// 清除超时定时器
clearTimeout(request_timer);
// 等待响应60秒超时
const response_timer = setTimeout(function () {
serares.destroy();
console.log('Response Timeout.');
}, 60000);
console.log("Got response: " + serares.statusCode);
let resData = '';
serares.on('data', function (chunk) {
resData += chunk;
});
serares.on('end', function () {
clearTimeout(response_timer);
log.logger.info('=======rData============================');
res.send(resData);
});
});
serareq.on("timeout", function () {
log.logger.info("timeout received");
if (serareq.serares) {
serareq.serares.emit("abort");
}
serareq.abort();
});
// 设置请求超时时间5秒
request_timer = setTimeout(function () {
serareq.emit("timeout", { message: 'have been timeout...' });
log.logger.info('=====Request Timeout.=================');
}, 5000);
log.logger.info("Send packageData!!!!!!!!!!!!!!!!");
// 写入请求体
serareq.write(transtr);
serareq.end();
}
关键点总结
- 文件描述符限制:确保操作系统允许足够的文件描述符。
- 超时处理:合理设置超时时间,并确保在超时时正确处理请求。
- 资源释放:在请求完成后及时释放资源,避免占用过多文件描述符。
通过这些方法,你可以有效避免 unhandled exception: Error: accept EMFILE
错误,并提高 Node.js 应用程序的稳定性和性能。
求解啊
open file 數量達上限 默認是1024 你用 ulimit -a看看
// 等待响应60秒超时
var response_timer = setTimeout(function() {
serares.destroy();
console.log('Response Timeout.');
}, 60000);
这个不应该放在回调里吧。
求解啊…socket hand up是什么原因
有一种情况是response end了之后,继续写入内容
关键socket hand up是什么原因 代码没写错吧?
这个是设置响应超时…是应该放在回调里面的…请求超时和响应超时都写了…
问题分析
EMFILE
错误通常表示 Node.js 进程打开的文件描述符(包括网络连接)超过了系统允许的最大数量。这通常是由于短时间内创建了大量未关闭的 socket 导致的。
解决方案
1. 增加文件描述符限制
你可以通过增加 Node.js 进程的文件描述符限制来解决这个问题。可以通过修改系统配置或启动 Node.js 应用时调整 ulimit 来实现。
例如,在启动 Node.js 应用前,运行以下命令:
ulimit -n 4096
这将把文件描述符限制提高到 4096。
2. 优化代码逻辑
确保在处理完请求后正确关闭 socket,并且在超时后正确销毁 socket。你的代码中已经有一些尝试,但可以进一步优化。
示例代码优化
const http = require('http');
function handleRequest(req, res) {
const transtr = '*******';
const options = {
host: 'xxxxxxxxxxxx',
port: 80,
path: '/ajax/requestHead.do',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(transtr),
'Connection': 'close'
}
};
console.log(transtr + '----------------------------------------');
const request_timer = setTimeout(() => {
serareq.abort();
log.logger.info('=====Request Timeout.=================');
}, 5000);
const response_timer = null;
const serareq = http.request(options, (serares) => {
clearTimeout(request_timer);
serares.setEncoding('utf8');
const resData = '';
serares.on('data', (respData) => {
resData += respData;
});
serares.on('end', () => {
res.send(resData);
log.logger.info('=======rData============================');
});
});
serareq.on("timeout", () => {
log.logger.info("timeout received");
serareq.abort();
});
serareq.on('error', (err) => {
log.logger.error('Request error:', err.message);
res.status(500).send('Internal Server Error');
});
serareq.write(transtr);
serareq.end();
}
const server = http.createServer(handleRequest);
server.listen(3000, () => {
console.log('Server running on port 3000');
});
总结
通过增加文件描述符限制和优化代码逻辑,可以有效避免 EMFILE
错误。确保在处理完请求后正确关闭 socket,并在超时后正确销毁 socket。