I/O多路轉接 --- UNIX環境高級編程

     I/O多路轉接技術:先構造一張有關描述符的列表,然後調用一個函數,知道這些描述符中的一個已準備好進行I/O時,給函數才返回。在返回時,它告訴進程哪些描述符已準備好可以進行I/O。

        poll、select、pselect這三個函數使我們能夠執行I/O多路轉接。


1.select和pselect函數

      I/O多路轉接的標準函數,還有一個標準函數poll函數,就這兩個
       該函數主要用於終端I/O和網絡I/O,但它對其他描述符同樣起作用。

      #include <sys/selecet.h>
     int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

    傳向select的參數告訴內核,我們所關心的描述符;對於每個描述符我們所關心的狀態;願意等待多長時間;返回值告訴我們,已準備好的的描述符的數量;對於讀、寫、異常者三個狀態中的每一個,哪些描述符已準備好;所以,只用這些返回值,就可調用相應的I/O函數(一般是read和write),並且確知該函數不會阻塞。


 參數意義:
    timeout:它指等待的時間:struct timeval{ long tv_sec; long tv_usec; };
             timeout = NULL; 永遠等待。如果捕捉到一個信號則終端此無限期等待。當所指定的描述符中的一個已準備好或捕捉到一個信號則返回。如果捕捉到信號一個信號,則返回-1,errno設置爲EINTR。
            timeout->tv_sec == 0 && timeout->tv_usec == 0; 完全不等待。測試所有描述符並立即返回。
            timeout->tv_sec != 0 && timeout->tv_usec != 0; 等待指定的秒數和微秒數。當指定的描述符之一已準備好,或當指定的時間值已經超過時立即返回。超時但沒有一個描述符準備好則返回0,

  中間3個參數readfds、writefds、exceptfds是指向描述符集的指針。這三個描述符集說明了我們關心的可讀、可寫、=或異常條件的哥哥描述符。每個描述符集存放在一個fs_set數據類型中。這種數據類型爲每一可能的描述符保持了一位。

   #include <sys/select.h>
          void FD_CLR(int fd, fd_set *set); 將指定位清掉
          int  FD_ISSET(int fd, fd_set *set); 測試儀指定位是否設置;若fd在集中則返回非0,否則返回0;
                            從select返回時,用其測試該集中的一個給定位是否仍舊設置
          void FD_SET(int fd, fd_set *set); 設置一個指定位
          void FD_ZERO(fd_set *set); 清楚所有位,在聲明一個描述符集後,必須先清楚所有位。

   中間的三個參數中任意一個或全部都可是NULL,表示對相應的狀態不關心,如果都爲空指針,則select提供了較sleep更精確的定時。
  
  第一個參數nfds,“最大描述符加1”。在3個描述符集中,找出最大描述符編號值,然後加1,就是第一個參數的值。第一個參數實際是要檢查的描述符的個數


 返回值:
                  -1。表示出錯,例如在所指定的描述符都沒有準備好時捕捉到一個信號,在此情況下,將不修改其中任何描述符集。
                 0。表示沒有描述符準備好。指定的描述符都沒有準備好,指定的時間已經超過,則發生這種情況。此時,所有的描述符皆被清0。
                 正返回值。表示已準備好的描述符的個數。是3個描述集中已準備好的描述符數之和,所以同一個描述符已準備好好讀和寫,返回值中將其記爲2.

   對於“已準備好”的意思做一些具體說明:
       若對讀集(readfds)中的一個描述符的read操作將不會阻塞,則此描述符準備好了
       若對寫集(writefds)中的一個描述符的write操作將不會阻塞,則此描述符準備好了
       若異常狀態急(exceptfds)中個一個描述符有一個未決異常狀態,則此描述符準備好了


          對於讀、寫、異常狀態,普通文件描述符總是返回準備好。
           一個描述符阻塞與否並不影響select是否阻塞。
          如果在一個描述符上碰到了文件結尾處,則select認爲該描述符是可讀的,然後調用read,返回0。不要認爲到達結尾處,select會只是一個異常狀態。


    POSIX.1也定義了一個select的變體,它被稱爲pselect


       #include <sys/select.h>

       int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask);

  除了一下幾點外,pselect與select相同:

2.poll函數(多路I/O轉接的標準函數之一,還有一個select)
 與select函數類似,返回值與select相同

 #include <poll.h>
 int poll(struct pollfd *fds, nfds_t nfds, int timeout);
 與select不同,poll不是爲每個狀態(讀、寫、異常)構造一個描述符集,而是構造一個pollfd結構體數組。每個數組元素指定一個描述符編號以及對其關心的狀態。


 參數:
  第一個參數是結構體數組。struct pollfd{int fd; short events; short revents; };
   每個數組元素的events成員設置的值見表,通過這些值告訴內核我們對描述符關心的是什麼。返回時,內核設置revents成員,說明對該描述符已經發生了什麼
   【注意】poll函數沒有更改events成員,這與select不同,select修改其參數以指示哪一個描述符已準備好。
    


   當一個描述符被掛斷(POLLHUP)後,就不能再寫向該描述符。但仍可能從該描述符讀取到數據

  第二個參數,nfds。fds數組中的元素數由nfds說明

  第三個參數timeout。
            -1.永遠等待。返回值情況與select相同
            0.不等待。測試所有描述符並立即返回。
            >0。等待timeout毫秒。返回值情況與select相同。
              【注】如果系統不提供毫秒級分辨率,則timeout值取整到最近的支持值。


 文件結束與掛斷之間的區別。
           如果正從終端輸入數據,並鍵入文件結束字符,POLLIN打開,於是就可讀文件結束指示(read返回0)。POLLHUP在revents中沒有打開。
           如果正在讀調制解調器,並且電話線已掛斷,則在revents中將接到POLLHUP通知。


 與select一樣。不論一個描述符是否阻塞,都不影響poll是否阻塞。

 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章