Unix下可用的五種 I/O 模型

介紹

當TCP客戶端同時處理兩個輸入時:標準輸入和TCP套接字,當客戶端fgets(在標準輸入上)被阻塞而且服務器進程被終止時,咱們遇到了問題服務器TCP正確地將FIN發送到客戶端TCP,但因爲客戶端進程被禁止從標準輸入讀取,因此它從沒有看到EOF,直到它從套接字讀取(可能更晚)。編程

若是一個或多個I / O條件準備好(即,輸入準備好被讀取,或者描述符可以得到更多輸出),咱們但願獲得通知。此功能稱爲 I/O 多路複用,由selectpoll函數以及前者的較新POSIX變體提供,稱爲pselect服務器

在如下場景中,I / O複用一般用於網絡應用程序:網絡

  • 當客戶端處理多個描述符(一般是交互式輸入和網絡套接字)時
  • 當客戶端同時處理多個套接字時(這是可能的,但不多見)
  • 若是TCP服務器同時處理偵聽套接字及其鏈接的套接字
  • 若是服務器同時處理TCP和UDP
  • 若是服務器處理多個服務而且可能處理多個協議

I / O複用不只限於網絡編程。許多重要的應用程序都須要這些技術。多線程

I / O模型

咱們首先檢查Unix下可用的五種 I/O 模型的基本差別:異步

  • 阻塞I / O.
  • 非阻塞I / O.
  • I / O多路複用(selectpoll
  • 信號驅動I / O(SIGIO
  • 異步I / O(POSIX aio_函數)

輸入操做一般有兩個不一樣的階段:async

  1. 等待數據準備就緒。這涉及等待數據到達網絡。當數據包到達時,它將被複制到內核中的緩衝區中。
  2. 將數據從內核複製到進程。這意味着將(就緒)數據從內核緩衝區複製到咱們的應用程序緩衝區中

阻塞I / O模型

最流行的I / O模型是阻塞I / O模型(咱們在前面的部分中使用了全部示例)。默認狀況下,全部套接字都是阻塞的。場景以下圖所示:函數

           

咱們在這個例子中使用UDP而不是TCP,由於對於UDP,數據「準備好」讀取的概念很簡單:要麼已經接收到整個數據報,要麼沒有接收到。使用TCP它會變得更復雜,由於插座的低水位標記等附加變量會起做用。spa

咱們還將recvfrom系統調用稱爲區分咱們的應用程序和內核,不管如何recvfrom實現(BSD getmsg上的系統調用和調用System V上的系統調用的函數)。一般會有一個從應用程序中運行到內核中運行的切換,以後會在一段時間後返回到應用程序。線程

在上圖中,進程調用recvfrom和系統調用在數據報到達並複製到應用程序緩衝區以前不會返回,或者發生錯誤。最多見的錯誤是系統調用被信號中斷咱們說過程從調用recvfrom到返回的整個時間都被阻止recvfrom成功返回時,咱們的應用程序處理的數據包。3d

非阻塞I / O模型

當一個套接字設置爲非阻塞時,咱們告訴內核「當我請求的I / O操做沒法在不使進程進入休眠狀態時完成時,不要讓進程進入休眠狀態,而是返回錯誤」。該圖以下:

           

  • 對於前三個recvfrom,沒有數據要返回,內核當即返回錯誤EWOULDBLOCK
  • 咱們第四次調用recvfrom,數據報就緒,它被複制到咱們的應用程序緩衝區,並recvfrom成功返回。而後咱們處理數據。

當一個應用程序坐在循環中調用recvfrom這樣的非阻塞描述符時,它被稱爲輪詢應用程序不斷輪詢內核以查看某些操做是否已準備就緒。這一般是浪費CPU時間,但偶爾會遇到此模型,一般在專用於一個功能的系統上。

I / O多路複用模型

經過I / O多路複用,咱們在這兩個系統調用之一中調用selectpoll阻塞,而不是在實際的I / O系統調用中阻塞。該圖是I / O複用模型的摘要:

            

咱們阻塞調用select,等待數據報套接字可讀。select返回套接字可讀時,咱們而後調用recvfrom將數據報復制到咱們的應用程序緩衝區中。

與阻塞I / O模型相比 * 
  • 缺點:使用select須要兩個系統調用(selectrecvfrom)而不是一個
  • 優勢:咱們能夠等待多個描述符準備就緒(參見本章後面select函數
具備阻塞I / O的多線程 * 

另外一個密切相關的I / O模型是使用阻塞I / O的多線程。該模型很是相似於上面描述的模型,除了不使用select阻塞多個文件描述符,程序使用多個線程(每一個文件描述符一個),而後每一個線程能夠自由調用阻塞系統調用recvfrom

信號驅動的I / O模型

信號驅動I / O模型使用的信號,告訴內核與通知咱們SIGIO信號時,描述符已準備就緒。該圖以下:

           

  • 咱們首先爲信號驅動的I / O啓用套接字,並使用sigaction系統調用安裝信號處理程序此係統調用的返回是當即的,咱們的過程繼續進行; 它沒有被阻止。
  • 當準備好讀取數據報時,SIGIO將爲咱們的過程生成信號。咱們能夠:
    • 經過調用從信號處理程序讀取數據報recvfrom,而後通知主循環數據已準備好處理
    • 通知主循環並讓它讀取數據報。

這個模型的優勢是咱們在等待數據報到達時不會被阻塞。主循環能夠繼續執行,只需等待信號處理程序通知數據已準備好處理或數據報已準備好被讀取。

異步I / O模型

異步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模型的比較

下圖是五種不一樣I / O模型的比較。

           

前四個模型之間的主要區別在於第一個階段,由於前四個模型中的第二個階段是相同的:recvfrom當數據從內核複製到調用者的緩衝區時,進程被阻塞可是,異步I / O處理兩個階段,與前四個不一樣。

同步I / O與異步I / 

POSIX將這兩個術語定義以下:

  • 同步I / O操做會致使請求進程被阻塞,直到I / O操做完成。
  • 異步I / O操做不會致使請求進程被阻止。

使用這些定義,前四個I/O模型(阻塞,非阻塞,I/O多路複用和信號驅動I/O)都是同步的,由於實際的I/O操做(recvfrom)會阻止進程。只有異步I/O模型匹配異步I/O定義。

相關文章
相關標籤/搜索