當TCP客戶端同時處理兩個輸入時:標準輸入和TCP套接字,當客戶端fgets
(在標準輸入上)被阻塞而且服務器進程被終止時,咱們遇到了問題。服務器TCP正確地將FIN發送到客戶端TCP,但因爲客戶端進程被禁止從標準輸入讀取,因此它從沒有看到EOF,直到它從套接字讀取(可能更晚)。編程
若是一個或多個I / O條件準備好(即,輸入準備好被讀取,或者描述符可以得到更多輸出),咱們但願獲得通知。此功能稱爲 I/O 多路複用,由select
和poll
函數以及前者的較新POSIX變體提供,稱爲pselect
。服務器
在如下場景中,I / O複用一般用於網絡應用程序:網絡
I / O複用不只限於網絡編程。許多重要的應用程序都須要這些技術。多線程
咱們首先檢查Unix下可用的五種 I/O 模型的基本差別:異步
select
和poll
)SIGIO
)aio_
函數)輸入操做一般有兩個不一樣的階段:async
最流行的I / O模型是阻塞I / O模型(咱們在前面的部分中使用了全部示例)。默認狀況下,全部套接字都是阻塞的。場景以下圖所示:函數
咱們在這個例子中使用UDP而不是TCP,由於對於UDP,數據「準備好」讀取的概念很簡單:要麼已經接收到整個數據報,要麼沒有接收到。使用TCP它會變得更復雜,由於插座的低水位標記等附加變量會起做用。spa
咱們還將recvfrom
系統調用稱爲區分咱們的應用程序和內核,不管如何recvfrom
實現(BSD getmsg
上的系統調用和調用System V上的系統調用的函數)。一般會有一個從應用程序中運行到內核中運行的切換,以後會在一段時間後返回到應用程序。線程
在上圖中,進程調用recvfrom
和系統調用在數據報到達並複製到應用程序緩衝區以前不會返回,或者發生錯誤。最多見的錯誤是系統調用被信號中斷。咱們說過程從調用recvfrom
到返回的整個時間都被阻止。當recvfrom
成功返回時,咱們的應用程序處理的數據包。3d
當一個套接字設置爲非阻塞時,咱們告訴內核「當我請求的I / O操做沒法在不使進程進入休眠狀態時完成時,不要讓進程進入休眠狀態,而是返回錯誤」。該圖以下:
recvfrom
,沒有數據要返回,內核當即返回錯誤EWOULDBLOCK
。recvfrom
成功返回。而後咱們處理數據。當一個應用程序坐在循環中調用recvfrom
這樣的非阻塞描述符時,它被稱爲輪詢。應用程序不斷輪詢內核以查看某些操做是否已準備就緒。這一般是浪費CPU時間,但偶爾會遇到此模型,一般在專用於一個功能的系統上。
經過I / O多路複用,咱們在這兩個系統調用之一中調用select
或poll
阻塞,而不是在實際的I / O系統調用中阻塞。該圖是I / O複用模型的摘要:
咱們阻塞調用select
,等待數據報套接字可讀。當select
返回套接字可讀時,咱們而後調用recvfrom
將數據報復制到咱們的應用程序緩衝區中。
select
須要兩個系統調用(select
和recvfrom
)而不是一個select
函數)另外一個密切相關的I / O模型是使用阻塞I / O的多線程。該模型很是相似於上面描述的模型,除了不使用select
阻塞多個文件描述符,程序使用多個線程(每一個文件描述符一個),而後每一個線程能夠自由調用阻塞系統調用recvfrom
。
該信號驅動I / O模型使用的信號,告訴內核與通知咱們SIGIO
信號時,描述符已準備就緒。該圖以下:
sigaction
系統調用安裝信號處理程序。此係統調用的返回是當即的,咱們的過程繼續進行; 它沒有被阻止。SIGIO
將爲咱們的過程生成信號。咱們能夠:
這個模型的優勢是咱們在等待數據報到達時不會被阻塞。主循環能夠繼續執行,只需等待信號處理程序通知數據已準備好處理或數據報已準備好被讀取。
異步I / O由POSIX規範定義,而且已經協調了各類標準中出現的實時函數的各類差別,這些差別聚集在一塊兒造成當前的POSIX規範。
這些函數經過告訴內核啓動操做並在整個操做(包括從內核到緩衝區的數據副本)完成時通知咱們來工做。這個模型和信號驅動的I / O模型的主要區別在於,經過信號驅動的I / O,內核告訴咱們什麼時候能夠啓動I / O操做,可是使用異步I / O,內核告訴咱們I / O操做完成時。請參見下圖,例如:
咱們調用aio_read
(POSIX異步I / O函數以aio_
或開頭lio_
)並傳遞如下內核:
read
),lseek
),此係統調用當即返回,而且在等待I / O完成時不會阻止咱們的進程。
咱們假設在這個例子中,咱們要求內核在操做完成時生成一些信號。在將數據複製到咱們的應用程序緩衝區以前,不會生成此信號,這與信號驅動的I / O模型不一樣。
下圖是五種不一樣I / O模型的比較。
前四個模型之間的主要區別在於第一個階段,由於前四個模型中的第二個階段是相同的:recvfrom
當數據從內核複製到調用者的緩衝區時,進程被阻塞。可是,異步I / O處理兩個階段,與前四個不一樣。
POSIX將這兩個術語定義以下:
使用這些定義,前四個I/O模型(阻塞,非阻塞,I/O多路複用和信號驅動I/O)都是同步的,由於實際的I/O操做(recvfrom
)會阻止進程。只有異步I/O模型匹配異步I/O定義。