您现在的位置是:亿华云 > 人工智能
Node.js中关于Accept时Emfile的处理
亿华云2025-10-09 13:33:11【人工智能】0人已围观
简介本文转载自微信公众号「编程杂技」,作者theanarkh。转载本文请联系编程杂技公众号。EMFILE表示进程打开的文件描述符达到了上限,比如建立了一个TCP连接后,调用accept函数的时候就可能触发
本文转载自微信公众号「编程杂技」,中关作者theanarkh。中关转载本文请联系编程杂技公众号。中关
EMFILE表示进程打开的中关文件描述符达到了上限,比如建立了一个TCP连接后,中关调用accept函数的中关时候就可能触发这个错误。那么这个会导致什么问题呢?中关首先我们看看Node.js是如何处理连接的。
void uv__server_io(uv_loop_t* loop,中关 uv__io_t* w, unsigned int events) {
uv_stream_t* stream;
int err;
stream = container_of(w, uv_stream_t, io_watcher);
while (uv__stream_fd(stream) != -1) {
// 摘取一个TCP连接
err = uv__accept(uv__stream_fd(stream));
// 记录下来
stream->accepted_fd = err;
// 执行上层回调,回调里消费accepted_fd
stream->connection_cb(stream,中关 0);
// 下一个循环
}
}
当监听socket上可读事件触发的时候,Node.js就会执行uv__server_io进行处理。中关在uv__server_io中Node.js就会不断地调用accept摘取连接,中关然后执行回调处理该连接。中关这是中关正常的流程,那么如果accept出错了,中关那会怎么样?中关比如返回了EMFILE错误。
因为Node.js中,b2b供应网epoll的工作模式是水平触发,所以每轮事件循环中,uv__server_io都会被触发,然后执行accept,接着触发错误(如果还没有可用的文件描述符的话)。然而底层已完成三次握手的TCP连接无法得到处理,客户端也只能默默地在等待。Node.js选择的处理策略是关闭连接来通知客户端,服务器已经过载。我们看看Node.js具体是怎么做的。在初始化第一个Libuv stream的时候会首先预留一个文件描述符。
if (loop->emfile_fd == -1) {
err = uv__open_cloexec("/dev/null", O_RDONLY);
if (err < 0)
/* In the rare case that "/dev/null" isnt mounted open "/"
* instead.
*/
err = uv__open_cloexec("/", O_RDONLY);
if (err >= 0)
loop->emfile_fd = err;
}
我们看到Node.js打开了一个资源,服务器租用然后拿到了一个文件描述符保存到emfile_fd。当Node.js处理TCP连接的时候,这个emfile_fd可能就会被用上。
// 摘取TCP连接
err = uv__accept(uv__stream_fd(stream));
if (err < 0) {
// 文件描述符过载
if (err == UV_EMFILE || err == UV_ENFILE) {
err = uv__emfile_trick(loop, uv__stream_fd(stream));
if (err == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK))
break;
}
stream->connection_cb(stream, err);
continue;
}
我们看到当uv_accept返回UV_EMFILE错误的时候,会执行uv__emfile_trick。
static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
int err;
int emfile_fd;
if (loop->emfile_fd == -1)
return UV_EMFILE;
// 关闭预留的文件描述符,下面的uv_accept才能执行成果
uv__close(loop->emfile_fd);
loop->emfile_fd = -1;
// 循环关闭无法处理的TCP连接
do {
// 摘取TCP连接
err = uv__accept(accept_fd);
if (err >= 0)
// 关闭TCP连接,通知客户端服务器过载
uv__close(err);
} while (err >= 0 || err == UV_EINTR);
// 重新获取一个预留的文件描述符
emfile_fd = uv__open_cloexec("/", O_RDONLY);
if (emfile_fd >= 0)
loop->emfile_fd = emfile_fd;
return err;
}
我们看到uv__emfile_trick中关闭了所有无法处理的TCP连接,然后重新补充预留的文件描述符。正常来说uv_accept最后会返回UV_EAGAIN表示没有连接需要处理了,从而结束处理连接的整个逻辑。
很赞哦!(66)
相关文章
- 网站页面结构改版,仅是页面样式发生变化,不会对排名、收录有影响;只有涉及到页面URL改变,才会对网站排名、收录有影响。
- Linux容器技术的实现原理
- 15 行 Java 代码实现一个标准输出的进度条,其中的知识点你知道但并不一定会用
- 软件开发生命周期(SDLC)完全指南
- 公司名字不但要与其经营理念、活动识别相统一,还要能反映公司理念,服务宗旨、商品形象,从而才能使人看到或听到公司的名称就能产生愉快的联想,对商店产生好感。这样有助于公司树立良好的形象。
- 如何构建高可用的分布式系统?
- 有利于提高Xenomai 实时性的一些配置建议
- 什么?可以在 HTML 中直接插入 Python 代码?
- 4、企业无形资产:通用网站已成为企业网络知识产权的重要组成部分,属于企业的无形资产,也有助于提升企业的品牌形象和技术领先形象。它是企业品牌资产不可或缺的一部分。
- 如何做好“防御性编码”?