IO模型

socket在創建的時候默認是阻塞的。我們可以給socket系統調用的第二個參數船都SOCK_NONBLOCK標誌,或者通過fcntl系統調用的F_SETFL命令,將其設置爲非阻塞的。阻塞和非阻塞的概念能應用於所有的文件描述符,而不僅僅是socket。我們稱阻塞的文件描述符稱爲阻塞IO,成非阻塞的文件描述符爲非阻塞IO。

針對阻塞IO執行的系統調用可能因爲無法立即完成而被操作系統掛起,直到等待的事件發送爲止。比如客戶端通過connect向服務器發起連接時,connect將首先發送同步報文段給服務器,如何等到服務器返回確認報文段。如果服務器的確認報文段沒有立即到達客戶端則connect調用將會被掛起,直到客戶端收到確認報文段並喚醒connect調用。socket的基礎API中,可能被阻塞的系統調用包括accept send recv 和connect。

針對非阻塞IO執行的系統調用則總是立即返回,而不管事件是否已經發生。如果事件沒有立即發生,這些系統調用就返回-1,和出錯的情況一樣。此時我們必須根據errno來區分這兩種情況。對accept send 和recv而言,事件未發生時errno通常被設置未EAGAIN(意爲再來一次)或者EWOULDBLOCK(意爲期望阻塞),對於connect 而言,errno則被設置成EINPROGRESS(意爲在處理中)。

很顯然,我們只有在事件已經發生的情況下操作非阻塞IO,才能提高程序的效率。因此非阻塞IO通常要和其他的IO通知機制一起使用,比如IO複用和SIGIO信號。

IO複用是最常使用的IO通知機制。它指的是應用程序通過IO複用函數向內核註冊一組事件,內核通過IO複用函數吧其中就緒的事件通知給應用程序。linux上常用的IO複用函數是select poll和epoll_wait。需要指出的是,IO複用函數本身是阻塞的,它們能夠提高程序效率的原因在於它們同時監聽多個IO事件的能力。

SIGIO信號也可以用來報告IO事件。我們可以爲一個目標文件描述符指定宿主進程,那麼被指定的宿主進程將捕獲到SIGIO信號。這樣,當目標文件描述符上有事件發生時,SIGIO信號的信號處理函數將被觸發,我們也就可以在該信號處理函數中對目標文件描述符執行非阻塞IO操作。


發佈了211 篇原創文章 · 獲贊 514 · 訪問量 53萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章