伺服器編程中的文件描述符

来源:http://www.cnblogs.com/gaorong/archive/2017/06/10/6977814.html
-Advertisement-
Play Games

linux系統下一切皆文件,通過虛擬文件系統(VFS)的機制將所有底層屏蔽掉,用戶可以通過統一的介面來實現對不同驅動的操作,對於每一個文件需要一個引用來指示,此時文件描述符應用而生,文件描述符類似於widows下的handle,對於文件的大部分操作都是通過這個描述符來操作的,例如read,write ...


  linux系統下一切皆文件,通過虛擬文件系統(VFS)的機制將所有底層屏蔽掉,用戶可以通過統一的介面來實現對不同驅動的操作,對於每一個文件需要一個引用來指示,此時文件描述符應用而生,文件描述符類似於widows下的handle,對於文件的大部分操作都是通過這個描述符來操作的,例如read,write。對於每一個文件描述符,內核使用三種數據結構來管理。

(1)  每個進程在進程表中都有一個記錄項,每個記錄項中有一張打開文件描述符表,可將其視為一個矢量,每個描述符占用一項。與每個文件描述符相關聯的是:

  (a)  文件描述符標誌。 (當前只定義了一個文件描述符標誌FD_CLOEXEC)

  (b)  指向一個文件表項的指針。

(2)  內核為所有打開文件維持一張文件表。每個文件表項包含:

  (a)  文件狀態標誌(讀、寫、增寫、同步、非阻塞等 )。

  (b)  當前文件位移量。(即為lseek函數所操作的值)

  (c)  指向該文件v節點表項的指針。

(3)  每個打開文件(或設備)都有一個 v 節點結構。 v節點包含了文件類型和對此文件進行各種操作的函數的指針信息。對於大多數文件, v 節點還包含了該文件的 i 節點(索引節點)。這些信息是在打開文件時從盤上讀入記憶體的,所以所有關於文件的信息都是快速可供使用的。例如, i 節點包含了文件的所有者、文件長度、文件所在的設備、指向文件在盤上所使用的實際數據塊的指針等等點。

 

  經過上述文件系統的三層封裝,每層負責不同的職責,從上到下第一層用於標識文件,第二層用於管理進程獨立數據,第三層管理文件系統元數據,直接關聯一個文件。這種分層思想的一個優點就是上層可以復用下層的結構。可能有多個文件描述符項指向同一個文件表項,也可以有多個文件表項指向同一個V節點。

  如果兩個獨立的進程打開了同一個文件,打開此文件的每個進程都得到一個文件表項,但是兩個文件表項的V節點指針指向相同的V節點,這樣的安排使得每個進程都有他自己的對該文件的當前位移量,且支持不同的打開方式(O_RDONLY, O_WRONLY, ORDWR)。

  當一個進程通過fork創建出子進程後,此時父,子進程內的文件描述符共用同一個文件表項,也就是說父子進程的文件描述符的指向相同。一般我們會在fork後關閉掉各自不需要的fd,例如父子進程通過pipe或socketpair進行通信,往往會close掉自己不需要讀(或寫)的一端。只有在沒有文件描述符引用當前文件表項的時候,close操作才真正銷毀當前文件表項數據結構,有點類似於引用計數的思想。這也是網路編程中close和shutdown函數的區別,前者只有在最後一個使用該socket的句柄的進程關閉的時候才真正斷開連接,而後者毫不商量直接斷開一側連接。但是在多線程的環境中,由於父子線程共用地址空間,此時文件描述符共同擁有,只有一份,所以也就不能線上程內close掉自己不需要的fd,否則會導致其它需要該fd的線程也受影響。因為父,子進程內打開的文件描述符共用同一個文件表項,所以在某些系統的伺服器編程中,如果採用preforking模型(伺服器預先派生多個子進程,在每個子進程監聽listenfd來accept連接)就會導致驚群現象的發生,伺服器派生的多個子進程各自調用accept並因而均被投入睡眠,當第一個客戶連接到達時,儘管只有一個進程獲得連接,但是所有進程都被喚醒,這樣導致性能受損。參見UNP P657。

  同時如果fork之後調用exec,所有的文件描述符繼續保持打開狀態。這可以用來給exec後的程式傳遞某些文件描述符。同時文件描述符標誌FD_CLOEXEC 就是用來關閉exec時繼續保持開放的文件描述符的選項。

  也可以通過dup或fcntl顯式複製一個文件描述符,他們指向相同的文件表項。通過dup2將文件描述符複製到制定數值。

  每個進程都有一個文件描述符表,進程間獨立,兩個進程之間的文件描述符並無直接關係,所以在進程內可以直接傳遞文件描述符,但是如果跨越進程傳遞就失去了意義,unix可以通過sendmsg/recvmsg進行專門的文件描述符的傳遞(參見書UNP 15.7節)。每個進程的前三個文件描述符分別對應標準輸入,標準輸出,標準錯誤。但是一個進程可打開的文件描述符數量是有限制的,如果打開的文件描述符太多會出現”Too many open files”的問題。在網路伺服器中,通過listenfd調用調用accept時,體現為產生EMFILE錯誤,這主要是因為文件描述符是系統的一個重要資源,系統資源是有盡的,系統對單一進程文件描述符限制預設值一般是1024,使用ulimit -n命令可以查看。當然也可以調高進程文件描述符數目,但這是治標不治本的方法,因為處理高併發服務時,伺服器資源有限,難免資源枯竭。

  當結合epoll的水平觸發方式來監聽lisenfd的連接時,大量socket連接涌來如果不處理會塞滿TCP的連接隊列,listenfd會一直產生可讀事件,將伺服器陷入忙等待,用C++開源網路庫muduo作者陳碩的做法是事先準備一個空閑的文件描述符,當產生EMFILE錯誤時就先關閉這個空閑文件,獲得一個文件描述符名額,再accept拿到一個socket連接的文件描述符,隨後立刻close,這樣就優雅的斷開了與客戶端的連接,最後重新打開空閑文件,把”坑”填上,以備再次出現這種情況時使用。

 1 //在程式開頭先”占用”一個文件描述符
 2 
 3 int idlefd = open("/dev/null", O_RDONLY | O_CLOEXEC);
 4 …………
 5 
 6 //然後當出現EMFILE錯誤的時候處理這個錯誤
 7 
 8 peerlen = sizeof(peeraddr);
 9 connfd = accept4(listenfd,  (struct sockaddr*)&peeraddr, &peerlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
10 
11 if (connfd == -1)
12 {
13     if (errno == EMFILE)
14     {
15         close(idlefd);
16         idlefd = accept(listenfd, NULL, NULL);
17         close(idlefd);
18         idlefd = open("/dev/null", O_RDONLY | O_CLOEXEC);
19         continue;
20     }
21     else
22         ERR_EXIT("accept4");
23 }

  由於文件描述符涉及內容龐雜,此時僅作拋磚引玉,後期會持續更新....


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Apache主機一般支持.htaccess偽靜態,即可以實現綁定功能變數名稱到子目錄、一個空間多個站點。 ...
  • RAID防止硬碟物理損壞以及增加存儲設備的吞吐量,RAID常見的組合有0、1、5、和10 RAID0:至少需要兩塊硬碟,可以有效提高硬碟的性能和吞吐量,但沒有數據的冗餘和錯誤修複能力 將多塊硬碟通過硬體或軟體的方式串聯在一起,成為一個大的捲集,將數據依次寫到各個硬碟中,這樣性能會極大提升, 但若任意... ...
  • 命令 參數 說明 useradd 用於創建新的用戶 -d 指定用戶的家目錄(預設為/home/username) -D 顯示預設值 -e 新賬戶的過期日期,格式“YYYY-MM-DD” -g 指定一個初始用戶組(必須已經存在) -G 指定一個或多個擴展用戶組 -N 不創建同名的用戶組 -s 指定預設 ...
  • ADC0809轉換誤差+-1位,ADC0808轉換誤差+-5位 ...
  • 博主研究生所在的實驗室是搞雷達的,項目所涉及的板卡都是DSP+FPGA架構的,至於原因,只知道FPGA是並行的,用來處理速度要求高,運算結構簡單的大數據量過程或演算法,比如接收處理天線各陣元採樣的初始數據等;DSP是順序的,用來處理數據量較低但運算量較大的演算法,比如DBF演算法、矩陣求逆演算法等。看了下麵 ...
  • 1. 先用rpm -qa| grep vsftpd命令檢查是否已經安裝,如果ftp沒有安裝,使用yum -y install vsftpd 安裝,(ubuntu 下使用apt-get install vsftpd) 2. service vsftpd start / service vsftpd r ...
  • 在Ubuntu系統中配置3389遠程桌面連接,這樣,不需要vnc軟體也能夠看到linux系統的桌面了! ...
  • 情景 我們知道,read命令可以讀取文件內容,並把內容賦值給變數。 以如下的數據文件為例。 以上文件的四列分別為序號(index)、學號(number)、姓名(name)、年齡(age)。用shell腳本讀取該文件並輸出每行的值: 執行腳本,查看結果: 不知你發現沒有,這樣的實現方式有著明顯的弊端: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...