成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何優雅的處理 Accept 出現 Emfile 的問題

系統 Linux
在服務器的開發中,有時會遇到這種情況:當調用 accept 函數接受客戶端連接,函數返回失敗,對應的錯誤碼是 EMFILE, 它表示當前進程打開的文件描述符已達上限,此時,服務器不能再接受客戶端連接。

[[393901]]

本文轉載自微信公眾號「Linux開發那些事兒」,作者LinuxThings。轉載本文請聯系Linux開發那些事兒公眾號。

通常情況下,服務端調用 accept 函數會返回一個新的文件描述符,用于和客戶端之間的數據傳輸

在服務器的開發中,有時會遇到這種情況:當調用 accept 函數接受客戶端連接,函數返回失敗,對應的錯誤碼是 EMFILE, 它表示當前進程打開的文件描述符已達上限,此時,服務器不能再接受客戶端連接

當遇到上述問題,怎么合理的處理呢,下面就來分析一下

建立連接的流程

先簡單回顧下客戶端和服務器建立連接的流程,具體的如下圖所示:

1. 客戶端發起 SYN 請求

2. 服務器收到客戶端的 SYN 請求后,內核把連接放入半連接隊列,同時給客戶端返回一個 SYN + ACK

3. 客戶端向服務器返回一個確認的 ACK, 服務器收到本次 ACK 之后,三次握手完成,同時,內核把連接從半連接隊列中移除,創建新完全連接,加入到全連接隊列中

4. 應用層調用 accept 函數從全連接隊列中取出連接

上面的第 1、第 2、第 3 步是 TCP 的三次握手,它是由內核中TCP協議完成的, 第 4 步是應用層調用 accept 接口

在 epoll 中的問題

epoll 是 Linux中IO多路復用模型,在服務器的開發中有廣泛的應用,下面就以 epoll 為例來詳細說明

服務器端創建偵聽文件描述符 listenfd 之后, 向 epoll 注冊讀事件

當 epoll 檢測到 listenfd 上有讀事件發生,會立即通知應用層,應用層調用 accept 接受新連接,而此時進程打開的文件描述符數量已經達到上限了,所以每次 accept 都是失敗的

這里會出現以下幾個問題

  1. 由于 每次 accept 都失敗了,相當于 listenfd 上的可讀事件沒有處理,epoll 會不停的觸發 listenfd 上的可讀事件,應用層也就會不停的調用 accept,然后又出現 accept 調用失敗,如此這般不停的執行無效的循環,白白浪費了CPU的資源
  2. 上面提到服務器在不停的執行無效的循環, 將會引發另一個問題,如果此時有新客戶端連接到來,建立連接的過程會很慢

前面說的 epoll 默認是使用了水平觸發模式,如果使用垂直觸發模式會出現什么問題呢?

垂直觸發模式下,listenfd 從無讀事件狀態到有讀事件狀態時,才會通知到應用層,在應用層處理完 listenfd 上所有的讀事件之前,epoll 不會再通知應用層

也就是說,應用層收到 listenfd 上讀事件通知之后,需要把 listenfd 上所有的讀事件全部處理完,下次listenfd 上再有讀事件時,才會通知應用層

回到 accept 的問題上,在垂直觸發模式下,當 epoll 通知應用層 listenfd 上有可讀事件時,應用層調用 accept, 由于此時進程打開的文件描述符數量已經達到上限了,所以 accept 調用失敗

也即 listenfd 上的可讀事件還沒有處理,在應用層處理完 listenfd 上可讀事件之前,epoll 不會再通知應用層 listenfd 上有可讀事件

如果在應用層處理完 listenfd 上可讀事件之前,有新的客戶端連接到來,這個時候 epoll 是不會通知應用層 listenfd 上有可讀事件,這會導致一個嚴重的問題:accept 只要出現了 EMFILE的錯誤碼,就再也無法接受客戶端的連接了

所以,當出現 EMFILE 時,不管使用 epoll 的水平觸發模式還是垂直觸發模式都會存在問題

如何解決

EMFILE 表示進程打開的文件描述符數量達到上限了,可以把這個值調大些,但這治標不治本

本來系統設置文件描述符數量上限是為了限制進程對系統資源的過度占用,況且,這個值調整到多大合適呢,總不能無限大吧,所以調整上限值的方式不是最合適的方式

accept 成功時會返回一個新的文件描述符,如果此時進程打開的文件描述符數量已經達到上限了,就會返回失敗

假如此時能關閉一個空閑的文件描述符,讓出一個名額,再調用 accept 就會創建成功,這種方式具體的處理步驟如下:

1、事先準備一個空閑的文件描述符 idlefd,相當于先占一個"坑"位

2、調用 close 關閉 idlefd,關閉之后,進程就會獲得一個文件描述符名額

3、再次調用 accept 函數, 此時就會返回新的文件描述符 clientfd, 立刻調用 close 函數,關閉 clientfd

4、重新創建空閑文件描述符 idlefd,重新占領 "坑" 位,再出現這種情況的時候又可以使用

由于測試代碼比較長,這里就不貼了,感興趣可以通過文末的方式獲取,下面是處理 EMFILE 的偽代碼:

  1. int ret = accept( listenfd, (struct sockaddr*)&addr, sizeof(addr) ); 
  2.  
  3. if (-1 == ret) 
  4.   if ( errno == EMFILE ) 
  5.   { 
  6.      //關閉空閑文件描述符,釋放 "坑"位 
  7.      close(idlefd); 
  8.       
  9.      //接受 clientfd 
  10.      clientfd = accept( listenfd, nullptr, nullptr); 
  11.      //關閉 clientfd,防止一直觸發 listenfd 上的可讀事件 
  12.      close(clientfd); 
  13.       
  14.      //重新占領 "坑"位 
  15.      idlefd = ::open("/dev/null", O_RDONLY | O_CLOEXEC); 
  16.   } 

 

責任編輯:武曉燕 來源: Linux開發那些事兒
相關推薦

2021-06-02 00:29:08

Node.jsAcceptEmfile

2023-10-10 13:23:18

空指針異常Java

2018-01-24 19:59:03

數據庫Oracle壞塊

2022-02-15 08:38:04

錯誤邏輯異常編程程序

2022-05-16 09:03:29

CPU服務日志

2019-01-24 16:11:19

前端全局異常數據校驗

2021-06-17 09:32:39

重復請求并發請求Java

2015-11-26 10:53:45

LinuxWindowsMac OS

2017-07-26 11:32:50

NETRabbitMQ系統集成

2021-01-19 10:35:49

JVM場景函數

2020-10-16 11:48:06

服務器系統運維

2022-03-01 21:25:30

對象代碼Proxy

2024-09-26 10:51:51

2021-06-05 13:44:08

遞歸策略鏈表

2021-10-04 08:26:10

用戶名密碼信息

2025-02-27 09:39:56

JavaJava 8對象

2009-06-10 15:27:08

netbeans 編碼亂碼

2021-03-04 08:19:31

警告屏蔽函數

2018-06-24 09:27:55

線程Tomcat多線程

2025-02-10 09:49:00

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品中文字幕久久 | 中文字幕一区二区三区四区 | 91国内视频在线 | 成人在线视频一区二区三区 | 伊人久久大香线 | 四虎伊人 | 人妖av| 久久成人国产精品 | 欧美电影一区 | 999久久久| 国产精品久久久久久久久久久久冷 | 亚洲人va欧美va人人爽 | www.久草.com| 午夜精品一区 | 日韩中文字幕在线免费 | 美女久久久久久久久 | 免费在线观看h片 | 久久精品国产一区二区 | 日本不卡一区 | 在线色网 | 午夜电影网| 91麻豆精品国产91久久久久久 | 一区在线视频 | 成年人视频免费在线观看 | 久久久久久久久久久福利观看 | 成人三级视频 | 亚洲视频www| 在线欧美亚洲 | 91成人免费看片 | 精品一区二区三区91 | 国产精品久久久久不卡 | 中文一区二区视频 | 国产综合精品一区二区三区 | 日韩精品一区二区三区中文在线 | 欧美一级片在线播放 | 国产一级在线观看 | 99精品免费视频 | 一区二区免费看 | 精品国产乱码久久久久久蜜柚 | 久久九九99 | 日韩免费中文字幕 |