在linux網絡編程【1-3】中,咱們編寫的網絡程序僅僅是爲了瞭解網絡編程的基本步驟,實際應用當中的網絡程序並不會用那樣的。首先,若是服務器須要處理高併發訪問,一般不會使用linux網絡編程(三)中那樣的多進程方式,由於那樣至關耗系統資源。實際當中,網絡程序多使用select、poll、epoll等多路IO複用來進行編寫。在進入主題以前,咱們先來了解一下linux的IO模型。linux
現有的linux IO模型有5種:阻塞式IO模型,非阻塞式IO模型,IO複用模型,信號驅動式IO模型,異步IO模型。編程
關於阻塞、非阻塞、同步、異步,甚至併發等待,這些概念一直沒有很好的理解,特地翻閱一些資料和博文,彙總以下:服務器
1.阻塞IO模型網絡
在linux中,默認狀況下全部的socket都是blocking,當用戶進程調用了recvfrom這個系統調用,kernel就開始了IO的第一個階段:準備數據。對於network io來講,不少時候數據在一開始尚未到達(好比,尚未收到一個完整的UDP包),這個時候kernel就要等待足夠的數據到來。而在用戶進程這邊,整個進程會被阻塞。當kernel一直等到數據準備好了,它就會將數據從kernel中拷貝到用戶內存,而後kernel返回結果,用戶進程才解除block的狀態,從新運行起來。因此,blocking IO的特色就是在IO執行的兩個階段都被block了。併發
2.非阻塞IO模型異步
linux下,能夠經過設置socket使其變爲non-blocking,從圖中能夠看出,當用戶進程發出read操做時,若是kernel中的數據尚未準備好,那麼它並不會block用戶進程,而是馬上返回一個error。從用戶進程角度講 ,它發起一個read操做後,並不須要等待,而是立刻就獲得了一個結果。用戶進程判斷結果是一個error時,它就知道數據尚未準備好,因而它能夠再次發送read操做。一旦kernel中的數據準備好了,而且又再次收到了用戶進程的system call,那麼它立刻就將數據拷貝到了用戶內存,而後返回。因此,用戶進程實際上是須要不斷的主動詢問kernel數據好了沒有。這種模型須要用戶進程不斷的查詢內核,比較消耗cpu,因此應用得比較少。socket
3.IO多路複用模型async
IO multiplexing這個詞可能有點陌生,可是若是我說select,epoll,大概就都能明白了。有些地方也稱這種IO方式爲event driven IO。咱們都知道,select/epoll的好處就在於單個process就能夠同時處理多個網絡鏈接的IO。它的基本原理就是select/epoll這個function會不斷的輪詢所負責的全部socket,當某個socket有數據到達了,就通知用戶進程。函數
當用戶進程調用了select,那麼整個進程會被block,而同時,kernel會「監視」全部select負責的socket,當任何一個socket中的數據準備好了,select就會返回。這個時候用戶進程再調用read操做,將數據從kernel拷貝到用戶進程。
這個圖和blocking IO的圖其實並無太大的不一樣,事實上,還更差一些。由於這裏須要使用兩個system call (select 和 recvfrom),而blocking IO只調用了一個system call (recvfrom)。可是,用select的優點在於它能夠同時處理多個connection。高併發
在IO multiplexing Model中,實際中,對於每個socket,通常都設置成爲non-blocking,可是,如上圖所示,整個用戶的process實際上是一直被block的。只不過process是被select這個函數block,而不是被socket IO給block。
4.信號驅動的IO模型
首先經過sigaction系統調用註冊信號處理函數,而後當即返回,進程繼續運行,這一過程是非阻塞的。當數據準備好後,內核發送SIGIO信號給進程,進程收到該信號後,讀取準備好的數據。
5.異步IO模型
用戶進程發起read操做以後,馬上就能夠開始去作其它的事。而另外一方面,從kernel的角度,當它受到一個asynchronous read以後,首先它會馬上返回,因此不會對用戶進程產生任何block。而後,kernel會等待數據準備完成,而後將數據拷貝到用戶內存,當這一切都完成以後,kernel會給用戶進程發送一個signal,告訴它read操做完成了。
關鍵詞總結對比:
阻塞 | 調用進程一直被阻塞,直到操做完成。 |
非阻塞 | 在內核的數據還未準備好時,會當即返回。 |
同步 | 引發請求進程阻塞,直到IO操做完成。 |
異步 | 不會引發請求進程阻塞。所以上述五種IO模型只有第五種是異步IO模型。 |
從上面表格所列的咱們對阻塞非阻塞,同步異步的理解,咱們編寫的網絡程序基本上不多使用異步,至少我在工程代碼裏不多看到有異步代碼。事實上,咱們用的最多的模型應該是IO多路複用模型,且一般將其中的每個socket都設置爲非阻塞。
next.....