您好,登錄后才能下訂單哦!
這篇文章主要講解了“Node.js中處理Accept時出現Emfile的解決方法”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Node.js中處理Accept時出現Emfile的解決方法”吧!
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中,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" isn't 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表示沒有連接需要處理了,從而結束處理連接的整個邏輯。
感謝各位的閱讀,以上就是“Node.js中處理Accept時出現Emfile的解決方法”的內容了,經過本文的學習后,相信大家對Node.js中處理Accept時出現Emfile的解決方法這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。