網絡編程中常見的5種I/O模型

I/O模型linux


Unix下共有五種I/O模型:服務器

1>:阻塞I/O網絡

2>:非阻塞I/O多線程

3>:I/O多路複用異步

4>:信號驅動I/Osocket

5>:異步I/Oide


其中前四種是同步I/O模型,只有第五種是異步的。函數


同步與異步:spa

這裏的同步和兩個實體之間通訊中的同步的概念是不同的,這裏的同步是指關於這個I/O中的一系列動做都須要本身來完成,不管你是原地等待事件的發生(阻塞)仍是當某個事件已經準備好的時候你去完成後面的的動做(非阻塞)都屬於同步。線程

異步,它是指是調用另外一個執行者去完成,當執行者發現要處理的時間後調用你,你再完成這件事情,執行的過程和你的動做是不牽扯的。


阻塞與非阻塞:

阻塞是指,等待某個事件的發生,若是它沒有發生則一直等待下去直到事件發生爲止。

非阻塞,不須要死死的等待,當它有返回的時候再去處理。



1>阻塞I/O

使用的I/O函數,致使程序阻塞,等待數據,若是數據沒有準備好則一直等待。

例如咱們使用的阻塞式的socket建立套接字的時候,調用accept/recvfrom/connect...等都會是阻塞式的等待鏈接,請求或者數據的到來

wKiom1dGsfXDyS4kAAELa2AoTU8006.png

阻塞式的函數實現起來很簡單,但它有不少的問題,首先做爲一個網絡的服務器,阻塞式的等待會浪費大量的資源和時間,當服務器調用函數sendto給遠端的一個客戶端發送數據時,這時候不作其餘的事情那麼日後的動做都堵塞在後面,這樣顯然是不合適的,解決這種問題的方法每每是建立一個進程或者線程去解決這件事,由於進程的開銷遠遠地大於線程的開銷,因此使用多線程的方法解決是很行得通的。

阻塞式的I/O的好處就是它很是的穩定,他能保證鏈接保證接受和發送數據的肯定性,這是大多大的互聯網公司使用多線程的緣由,而且使用線程池也會大大增長線程開啓的效率。


2>非阻塞式I/O

調用socket函數並將其設置爲非阻塞模式,設置方式,linux下調用fcntl()函數。


非阻塞方式下,當前執行流再也不以睡眠的方式來等待請求或者數據的到來,而採用輪詢的方式,這種方式的運做流程是這樣的,每隔一個時間段便返回一次,若是有數據到來則返回,若是沒有,則返回一個錯誤碼WSAEWOULDBLOCK,咱們須要不斷的用循環來等待數據的成功返回,這個過程每每會佔用大量的CPU。

非阻塞的缺點,雖然他不用再使等待太僵硬,但它不可避免的一次只能等待一個事件的到來。



3>信號驅動I/O

在TCPsocket中發生如下事件均會產生SIGIO信號,由於在同一個時候產生這種信號的緣由太多咱們不能區分究竟是哪種狀況產生的SIGIO信號,因此在TCP中信號驅動是不太適合使用的,相反在UDP中卻比較適合使用。

wKioL1dGvRWSTO94AAEVwPhhXXo699.png


信號驅動的工做方式以下圖所示

wKiom1dGvFayufQTAAEiIK2Yzzs819.png


4>I/O多路複用。


這種方式下的工做方式就比較特別了,按TCPsocket來舉例,他會當listen到一個新的連接的時候將它放到一個集合中,當這個集合中的套接字有讀的狀況,咱們便讀取,有寫的狀況,咱們便寫,它是非阻塞I/O和信號驅動I/O再加上能夠等待多個,這三個的合體,常見的函數有select,poll,epoll等,這些函數會在後面的博客中細細講述。

它的缺點就是,不管是上面所述的哪一種函數,每次發送或者接受一個數據都會進入兩次內核與用戶的轉換。

I/O多路複用的模型以下圖


wKioL1dGv2aSl317AAEj_ol3zoo107.png



5>異步I/O

當一個異步過程調用發出後,調用者不能馬上獲得結果。實際處理這個調用的部件在完成後,經過狀態、通知和回調來通知調用者的輸入輸出操做

wKiom1dGvZmDVsONAADvg-gJtTE025.png




5種I/O模型的對好比下圖

wKioL1dGv-3j6GmbAAGTvufwcyQ834.png


能夠看出最好的方式是異步I/O了固然它實現起來比較負責,阻塞I/O的可靠性最好。

相關文章
相關標籤/搜索