IO多路復用總結

2021-07-22 09:02:25 字數 3178 閱讀 2712

講io多路復用之前我們先理解什麼是io?

我們都知道unix世界裡,一切皆檔案,而檔案是什麼呢?檔案就是一串二進位製流,不管socket,還是fifo、管道、終端,對我們來說,一切都是檔案,一切都是流。在資訊 交換的過程中,我們都是對這些流進行資料的收發操作,簡稱為i/o操作(input and output),往流中讀出資料,系統呼叫read,寫入資料,系統呼叫write。

那麼計算機中這麼多流,我們是如何知道要操作哪個流呢?這時候我們需要有乙個能夠對檔案進行定位的識別符號,那麼檔案描述符就應運而生。檔案描述符是核心為了高效管理已經被開啟的檔案所建立的索引,他是乙個從0開始的整數,程式所有執行的i/o操作都是通過檔案描述符進行的。其中,在程式剛剛啟動時,0,1,2三個檔案描述符已經被占用了,0代表標準輸入裝置stdin(比如鍵盤),1代表標準輸出裝置stdout(顯示器),2代表標準錯誤stderr.posix標準要求每次開啟檔案時(含socket)必須使用當前程序中最小可用的檔案描述符號碼,因此再開啟乙個檔案,它的檔案描述符會是3。

既然檔案描述符是檔案的索引,那麼它有沒有最大限制呢?對的,檔案描述符是系統的乙個重要的資源,實際中最大開啟的檔案數是系統記憶體的10%,這個是系統級限制,有系統就會有使用者,使用者級限制是單個程序最大開啟的檔案數,一般是1024,可以使用ulimit -n命令檢視。

系統是如何通過檔案描述符定位到檔案的呢?

系統為每乙個程序維護了乙個檔案描述符表,這是乙個程序級的檔案描述符表,它通過檔案描述符所對應的檔案指標指向系統級的開啟檔案描述符表中的乙個開啟檔案控制代碼,控制代碼中儲存了開啟檔案相應的全部資訊,包括檔案偏移量、狀態標示、訪問模式檔案型別以及檔案屬性等等,其中有乙個inode指標,它指向了i-node表中該檔案的表項,具體想要了解i-node表的可以檢視linux的inode的理解.此部落格寫的很詳細。

為了讓大家能順利掌握io復用,請允許我再嘮叨一下阻塞與非阻塞。

什麼是程式的阻塞呢?想象這種情形,比如你等快遞,但快遞一直沒來,你會怎麼做?有兩種方式:

快遞沒來,我可以先去睡覺,然後快遞來了給我打**叫我去取就行了。

快遞沒來,我就不停的給快遞打**說:擦,怎麼還沒來,給老子快點,直到快遞來。

很顯然,你無法忍受第二種方式,不僅耽擱自己的時間,也會讓快遞很想打你。

而在計算機世界,這兩種情形就對應阻塞和非阻塞忙輪詢。

非阻塞忙輪詢:資料沒來,程序就不停的去檢測資料,直到資料來。

阻塞:資料沒來,啥都不做,直到資料來了,才進行下一步的處理。

先說說阻塞,為了了解阻塞是如何進行的,我們來討論緩衝區,以及核心緩衝區,最終把i/o事件解釋清楚。緩衝區的引入是為了減少頻繁i/o操作而引起頻繁的系統呼叫(你知道它很慢的),當你操作乙個流時,更多的是以緩衝區為單位進行操作,這是相對於使用者空間而言。對於核心來說,也需要緩衝區。

因為乙個執行緒只能處理乙個套接字的i/o事件,如果想同時處理多個,可以利用非阻塞忙輪詢的方式,偽**如下:

while

true }

我們只要把所有流從頭到尾查詢一遍,就可以處理多個流了,但這樣做很不好,因為如果所有的流都沒有i/o事件,白白浪費cpu時間片。正如有一位科學家所說,計算機所有的問題都可以增加乙個中間層來解決,同樣,為了避免這裡cpu的空轉,我們不讓這個執行緒親自去檢查流中是否有事件,而是引進了乙個**(一開始是select,後來是poll),這個**很牛,它可以同時觀察許多流的i/o事件,如果沒有事件,**就阻塞,執行緒就不會挨個挨個去輪詢了,偽**如下:

while

true }

好了,我們講了這麼多,那麼,到底什麼是i/o多路復用呢?

我們知道阻塞io是阻塞乙個io,io多路復用就是同時阻塞多個io,官方點的解釋是指核心一旦發現程序指定的乙個或者多個io條件準備讀取,它就通知該程序。下面有一幅圖形象的體現出這一點:

io多路復用適用如下場合:

1. 當客戶處理多個描述符時(一般是互動式輸入和網路套介面),必須使用i/o復用。

2. 當乙個客戶同時處理多個套介面時,而這種情況是可能的,但很少出現。

3. 如果乙個tcp伺服器既要處理監聽套介面,又要處理已連線套介面,一般也要用到i/o復用。

4. 如果乙個伺服器即要處理tcp,又要處理udp,一般要使用i/o復用。

5. 如果乙個伺服器要處理多個服務或多個協議,一般要使用i/o復用。

與多程序和多執行緒技術相比,i/o多路復用技術的最大優勢是系統開銷小,系統不必建立程序/執行緒,也不必維護這些程序/執行緒,從而大大減小了系統的開銷。

上面說了那麼多,好像這裡並沒有用到什麼,別著急,下面來說下io復用的具體實現。

select, poll, epoll 都是i/o多路復用的具體的實現,之所以有它們三個存在,其實是他們出現是有先後順序的。

函式介紹:

該函式准許程序指示核心等待多個事件中的任何乙個傳送,並只在有乙個或多個事件發生或經歷一段指定的時間後才喚醒。函式原型如下:

include select.h>

include time.h>

intselect(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout)

返回值:就緒描述符的數目,超時返回0,出錯返回-1

函式引數介紹如下:

(1)第乙個引數maxfdp1指定待測試的描述字個數,它的值是待測試的最大描述字加1(因此把該引數命名為maxfdp1),描述字0、1、2…maxfdp1-1均將被測試。

因為檔案描述符是從0開始的。

(2)中間的三個引數readset、writeset和exceptset指定我們要讓核心測試讀、寫和異常條件的描述字。如果對某乙個的條件不感興趣,就可以把它設為空指標。struct fd_set可以理解為乙個集合,這個集合中存放的是檔案描述符,可通過以下四個巨集進行設定:

I O多路復用

一 五種i o模型 1 阻塞i o模型 最流行的i o模型是阻塞i o模型,預設情形下,所有套介面都是阻塞的。我們以資料報套介面為例來講解此模型 我們使用udp而不是tcp作為例子的原因在於就udp而言,資料準備好讀取的概念比較簡單 要麼整個資料報已經收到,要麼還沒有。然而對於tcp來說,諸如套介面...

i o多路復用

最常見的i o多路復用就是 select poll epoll了,下面說說他們的一些特點和區別吧。select 可讀 可寫 異常三種檔案描述符集的申明和初始化。fd set readfds,writefds,exceptionfds fd zero readfds fd zero writefds ...

I O多路復用

我們都知道unix like 世界裡,一切皆檔案,而檔案是什麼呢?檔案就是一串二進位製流而已,不管socket,還是fifo 管道 終端,對我們來說,一切都是檔案,一切都是流。在資訊 交換的過程中,我們都是對這些流進行資料的收發操作,簡稱為i o操作 input and output 往流中讀出資料...