本文是對《UNIX網絡編程卷1》第6章的總結。 編程
1、 什麼是IO複用? 緩存
它是內核提供的一種同時監控多個文件描述符狀態改變的一種能力;例如當進程須要操做多個IO相關描述符時(例如服務器程序要同時查看監聽socket和大量業務socket是否有數據到來),須要內核可以監控這許多描述符,一旦這些描述符有就緒(或者狀態改變了)就告訴主動告訴進程哪些描述符已經就緒,這樣站在進程的角度,就不須要挨個的查看每一個描述符是否就緒。 服務器
2、 IO操做分爲兩個階段: 網絡
(1) 準備階段,例如輸入操做時要等待數據已經就緒,輸出操做時緩衝區中有空間可供使用; 異步
(2) 數據拷貝階段,例如輸入操做時將數據從內核複製到用戶緩存,輸出操做時將用戶緩存複製到內核。 socket
以讀取系統調用recvfromfrom爲例,每當用戶進程發起一個recvfrom操做,站在用戶進程的角度,其實它包含上述兩個請求:第一個請求就是看看數據是否是準備好了,若是沒有準備好就把我阻塞那裏(對應阻塞IO)或者給我返回個沒有準備好的標誌(對應非阻塞IO);第二個請求就是在數據就緒的時候將數據拷貝給用戶進程。 函數
3、 Unix環境下有5中IO模型 spa
(1)阻塞IO模型 .net
(2)非阻塞IO模型 blog
(3)IO複用模型
(4)信號驅動IO模型
(5)異步IO模型
其中(1)~(4)都屬於同步IO,(5)屬於異步IO,由於前4中模型在第一階段的準備階段有區別,在第二階段的數據拷貝過程當中都會阻塞用戶進程,而(5)在第一階段的準備階段和第二階段的數據拷貝過程都不會阻塞用戶進程。
4、 各類模型的詳細區別
(1) 阻塞IO模型
阻塞IO模型中,以數據接收爲例,進程調用recvfrom系統調用向內核請求讀取數據,其內部過程將以下圖1所示:
圖1阻塞IO模型
由圖1能夠看到用戶進程從發起recvfrom系統調用開始後的兩個階段都被阻塞。
(2) 非阻塞IO模型
以讀取數據爲例,非阻塞模型中,進程須要先把socket設置爲非阻塞模式,這樣內核在準備數據時就不會阻塞該系統調用,而是直接返回EWOULDBLOCK,在讀取操做時,用戶進程同樣是調用recvfrom向內核請求數據,其內部過程以下圖2所示:
圖2 非阻塞模式IO模型
由上圖2能夠看到非阻塞模式中,在數據準備階段,系統調用不會被阻塞,可是在數據複製階段也會被阻塞;所以這裏所說的阻塞是指數據準備階段是否被阻塞,而不是數據拷貝階段。
(3) IO複用模型
IO複用模型中,進程可讓內核監控多個描述符的就緒狀態,通常使用的接口函數爲select或者poll,內核經過select查詢到所監控的描述符中有就緒的,則把就緒的描述符返回給調用進程,進程再調用recvfrom實際讀取數據,其內部過程大體以下圖3所示:
圖3 、IO複用模型
由上圖能夠看出,在IO複用模型中,用戶進程先調用select或者poll查看是否有數據就緒,若是有數據就緒再調用recvfrom去讀取數據,系統在階段1和階段2都將會被阻塞,可是阻塞於不一樣的系統調用(階段1阻塞於select或者poll,階段2阻塞於recvfrom)。
(4) 信號驅動IO模型
信號驅動IO模型是讓內核在描述符就緒時發送SIGIO信號通知用戶進程。在使用信號驅動模型進行IO操做時,首先要打開socket使用信號驅動IO的能力;而後調用sigaction系統調用設置信號SIGIO的處理函數,sigaction系統調用不會被阻塞。這樣就能夠在信號處理函數中讀取數據了,其處理過程以下圖4所示:
圖4 信號驅動IO模型
由上圖4能夠看出,信號驅動模型只要設置好信號處理函數後就能夠進行其餘操做了,當有數據到來時內核將會通知進程進行處理;與非阻塞IO模型相比,信號驅動IO模型不須要在準備數據時輪詢是否準備好。
(5) 異步IO模型
異步IO模型中,用戶進程發起讀取調用以後會當即返回,待內核接收到數據並將數據拷貝到用戶進程空間以後,再通知用戶進程,其過程以下圖5所示:
圖5異步IO模型
5、5中IO模型的比較
上述5中IO操做模型的區別能夠參見圖6所示:
圖六、5中IO模型的比較
同步IO:致使請求進程阻塞,直到IO操做完成;
異步IO:不致使請求阻塞;
所以,前面介紹的5中模型中,前4中IO模型都屬於同步IO,由於他們第二階段的複製數據過程將阻塞用戶進程,只有第5種纔是真正的異步IO模型。