1 阻塞I/O(blocking IO)
應用程序調用一個IO函數,導致應用程序阻塞,如果數據已經准備好,從內核拷貝到用戶空間,否則一直等待下去。一個典型的讀操作流程大致如下圖,當用戶進程調用recvfrom這個系統調用時,kernel就開始了IO的第一個階段:准備數據,就是數據被拷貝到內核緩沖區中的一個過程(很多網絡IO數據不會那么快到達,如沒收一個完整的UDP包),等數據到操作系統內核緩沖區了,就到了第二階段:將數據從內核緩沖區拷貝到用戶內存,然后kernel返回結果,用戶進程才會解除block狀態,重新運行起來。blocking IO的特點就是在IO執行的兩個階段用戶進程都會block住;

2 非阻塞I/O(nonblocking IO)
非阻塞I/O模型,我們把一個套接口設置為非阻塞就是告訴內核,當所請求的I/O操作無法完成時,不要將進程睡眠,而是返回一個錯誤。這樣我們的I/O操作函數將不斷的測試數據是否已經准備好,如果沒有准備好,繼續測試,直到數據准備好為止。在這個不斷測試的過程中,會大量的占用CPU的時間。
當用戶進程發出read操作時,如果kernel中數據還沒准備好,那么並不會block用戶進程,而是立即返回error,用戶進程判斷結果是error,就知道數據還沒准備好,用戶可以再次發read,直到kernel中數據准備好,並且用戶再一次發read操作,產生system call,那么kernel 馬上將數據拷貝到用戶內存,然后返回;所以nonblocking IO的特點是用戶進程需要不斷的主動詢問kernel數據好了沒有。
阻塞IO一個線程只能處理一個IO流事件,要想同時處理多個IO流事件要么多線程要么多進程,這樣做效率顯然不會高,而非阻塞IO可以一個線程處理多個流事件,只要不停地詢所有流事件即可,當然這個方式也不好,當大多數流沒數據時,也是會大量浪費CPU資源;為了避免CPU空轉,引進代理(select和poll,兩種方式相差不大),代理可以觀察多個流I/O事件,空閑時會把當前線程阻塞掉,當有一個或多個I/O事件時,就從阻塞態醒過來,把所有IO流都輪詢一遍,於是沒有IO事件我們的程序就阻塞在select方法處,即便這樣依然存在問題,我們從select出只是知道有IO事件發生,卻不知道是哪幾個流,還是只能輪詢所有流,epoll這樣的代理就可以把哪個流發生怎樣的IO事件通知我們;

3 I/O多路復用模型(IO multiplexing)
I/O多路復用就在於單個進程可以同時處理多個網絡連接IO,基本原理就是select,poll,epoll這些個函數會不斷輪詢所負責的所有socket,當某個socket有數據到達了,就通知用戶進程,這三個functon會阻塞進程,但和IO阻塞不同,這些函數可以同時阻塞多個IO操作,而且可以同時對多個讀操作,寫操作IO進行檢驗,直到有數據到達,才真正調用IO操作函數,調用過程如下圖;所以IO多路復用的特點是通過一種機制一個進程能同時等待多個文件描述符,而這些文件描述符(套接字描述符)其中任意一個進入就緒狀態,select函數就可以返回。
IO多路復用的優勢在於並發數比較高的IO操作情況,可以同時處理多個連接,和bloking IO一樣socket是被阻塞的,只不過在多路復用中socket是被select阻塞,而在阻塞IO中是被socket IO給阻塞。

4信號驅動I/O模型
可以用信號,讓內核在描述符就緒時發送SIGIO信號通知我們,通過sigaction系統調用安裝一個信號處理函數。該系統調用將立即返回,我們的進程繼續工作,也就是說它沒有被阻塞。當數據報准備好讀取時,內核就為該進程產生一個SIGIO信號。我們隨后既可以在信號處理函數中調用recvfrom讀取數據報,並通知主循環數據已經准備好待處理。特點:等待數據報到達期間進程不被阻塞。主循環可以繼續執行,只要等待來自信號處理函數的通知:既可以是數據已准備好被處理,也可以是數據報已准備好被讀取

5異步 I/O(asynchronous IO)
異步IO告知內核啟動某個操作,並讓內核在整個操作(包括將內核數據復制到我們自己的緩沖區)完成后通知我們,調用aio_read(Posix異步I/O函數以aio_或lio_開頭)函數,給內核傳遞描述字、緩沖區指針、緩沖區大小(與read相同的3個參數)、文件偏移以及通知的方式,然后系統立即返回。我們的進程不阻塞於等待I/0操作的完成。當內核將數據拷貝到緩沖區后,再通知應用程序。
用戶進程發起read操作之后,立刻就可以開始去做其它的事。而另一方面,從kernel的角度,當它受到一個asynchronous read之后,首先它會立刻返回,所以不會對用戶進程產生任何block。然后,kernel會等待數據准備完成,然后將數據拷貝到用戶內存,當這一切都完成之后,kernel會給用戶進程發送一個signal,告訴它read操作完成了

