最近工做接觸到了網絡服務同步和異步,因此學習了下《UNIX網絡編程》,在此做下總結。編程
輸入/輸出(I/O)是在主存和外部設備(如磁盤驅動器、終端和網絡)之間拷貝數據的過程。輸入是從I/O設備拷貝數據到主存,而輸出是從主存拷貝數據到I/O設備。好比,網絡可視爲一個I/O設備,做爲數據源和數據接收方。系統能夠通過網絡讀取其餘機器發送來的數據,並將數據複製到本身主存中。 網絡
下面分別介紹Unix的5種I/O模型:多線程
一個輸入操做一般爲如下兩個階段:異步
(1)等待數據準備好;socket
(2)從內核複製數據到進程;函數
拿網絡中客戶端請求服務的例子說明五種模型。學習
在網絡請求中,套接字(socket)是實現通訊的一個端點,應用程序能夠經過它發送或接收數據,可對其進行像對文件同樣的打開、讀寫和關閉等操做。線程
對於一個soket上的輸入操做:3d
(1)等待數據從網絡中到達。數據到達時被複制到內核中的緩衝區;指針
(2)把數據從內核緩衝區複製到應用進程緩衝區。
阻塞式IO模型是最經常使用的,咱們將recvfrom做爲系統調用,來觀察應用進程和內核之間的區別。下圖中進程調用recvfrom,該系統調用直到數據報準備好且拷貝到應用緩衝區或者出錯才返回,也就是說在數據返回以前,進程被阻塞,當進程返回成功指示後,才能夠開始下面的處理。
下圖中,前三次調用recvfrom,數據還沒準備好,內核會當即返回一個EWOULDBLOCK錯誤,直到第四次調用時,數據準備好被拷貝到應用緩衝區,該系統調用返回成功指示,接下來開始處理數據。當應用進程像這樣對一個非阻塞描述字循環調用recvfrom時,這實際上就是輪詢(polling)。
應用程序不斷地查詢內核,檢查數據是否準備好,這對CPU來講是一種浪費,因此這種模型比較少見。
IO複用是指經過調用select,poll或者epoll函數,監聽多個socket鏈接,每新來一個socket鏈接,就會被加入到監聽列表,實現單個線程同時處理多個網絡鏈接的IO。基本原理是經過select,poll或epoll不斷輪詢負責的所有socket,當其中一個數據準備好,就通知進程。而後調用recvfrom拷貝數據從內核到進程,返回成功指示後,進行下一步處理。
應用進程雖然不會被socket的IO阻塞,但一直被select,poll或epoll阻塞。若是socket數不是不少的話,使用IO複用模型可能比多線程 + 阻塞IO延遲更大,由於IO複用模型相對比以前的模型須要兩次系統調用,它的優點在於能處理較多的鏈接。
該模型經過系統調用sigaction安裝一個信號處理程序。當內核準備好數據後,發送信號告知進程。在信號處理程序中調用recvfrom讀取數據,並通知主循環。這種模型的好處是當等待數據報到達時,IO不被阻塞。主循環能夠繼續執行,只是等待信號處理程序的通知:數據已準備好被讀。
異步IO模型讓內核完成整個操做(包括將數據從內核拷貝到進程緩衝區)後才進行通知應用進程。這個模型和信號驅動模型的主要區別在於:信號驅動IO是由內核通知咱們什麼時候能夠啓動一個IO操做,而異步IO是由內核通知咱們IO操做什麼時候完成。
下圖中調用aio_read,傳遞內核描述字、緩衝區指針、緩衝區大小、文件偏移,並告訴內核整個操做完成時如何通知咱們。該系統調用當即返回,不阻塞於IO操做。該圖中,內核在操做完成後傳遞一個信號,該信號直到數據被拷貝到緩衝區才產生,這是和信號驅動IO的不一樣之處。
從這兩個階段來看,前四種模型在第一階段有所不一樣,但第二個階段基本相同,把數據從內核拷貝到應用進程的緩衝區時,進程被阻塞於recvfrom調用。異步IO模型的兩個階段都不一樣於前四種模型。
同步IO操做會阻塞請求進程,直到IO操做完成。
異步IO操做不會阻塞請求進程。
前四種模型:阻塞IO模型、非阻塞IO模型、IO複用模型和信號驅動IO都是同步IO模型,由於真正的IO操做(recvfrom)阻塞進程。