linux內(nèi)核將所有外部設(shè)備都看做一個文件來操作。對該文件的讀寫操作會調(diào)用內(nèi)核提供的系統(tǒng)命令, 返回一個fd(file descriptor)文件描述符。而對一個socket的讀寫也有相應(yīng)的描述符即 socketfd。 描述符即一串?dāng)?shù)字,指向內(nèi)核中的一個結(jié)構(gòu)體 Unix、Linux提供五種 i/o 模型,分別如下:
最常用的I/O模型就是阻塞I/O模型。缺省情況下,所有文件操作都是阻塞的。我們以套接字接口為例講解此模型:在進(jìn)程空間中調(diào)用recvfrom,其系統(tǒng)調(diào)用直到數(shù)據(jù)包到達(dá)被復(fù)制到應(yīng)用進(jìn)程中的緩沖區(qū)中或者發(fā)生錯誤時才返回。在此期間一直會等待,進(jìn)程在從調(diào)用recvfrom開始到它返回的整段時間內(nèi)都是被阻塞的。 流程如下圖: 
recvfrom從應(yīng)用層到內(nèi)核的時候,如果該緩沖區(qū)沒有數(shù)據(jù)的話,就直接返回一個EWOULDBLOCK錯誤,一般都對非阻塞I/O模型進(jìn)行輪詢檢查這個狀態(tài),看內(nèi)核是否有數(shù)據(jù)到來,流程如下圖: 
linux提供select/poll,進(jìn)程通過將一個或多個fd傳遞給select或poll系統(tǒng)調(diào)用,阻塞在select操作上,這樣select/poll可以幫我們偵測多個fd是否處在就緒狀態(tài)。select/poll順序掃描fd是否就緒,且支持fd數(shù)量有限,因此它的使用受到一些制約。linux還提供一個epoll系統(tǒng)調(diào)用,epoll使用基于事件驅(qū)動方式代替順序掃描,因此性能更高,當(dāng)有fd就緒時,立即回調(diào)函數(shù)rollback。流程如下圖: 
首先開啟套接口信號驅(qū)動I/O功能,并通過系統(tǒng)調(diào)用sigaction執(zhí)行一個信號處理函數(shù)(此系統(tǒng)調(diào)用立即返回,進(jìn)程繼續(xù)工作,它是非阻塞的)。當(dāng)數(shù)據(jù)準(zhǔn)備就緒時,就為該進(jìn)程生成一個sigio信號,通過信號回調(diào)通知應(yīng)用程序調(diào)用recvfrom來讀取數(shù)據(jù),并通知主循環(huán)函數(shù)處理數(shù)據(jù)。流程如下圖: 
告知內(nèi)核啟動某個操作,并讓內(nèi)核在整個操作完成后(包括將數(shù)據(jù)從內(nèi)核復(fù)制到用戶自己的緩沖區(qū))通知我們。這種模型與信號驅(qū)動模型的主要區(qū)別是:信號驅(qū)動I/o由內(nèi)核通知我們何時可以開始一個I/o操作;異步I/o模型由內(nèi)核通知我們I/o操作何時已經(jīng)完成。流程如圖:
參考 《Unix 網(wǎng)絡(luò)編程》
新聞熱點
疑難解答