Linux程式設計 IO復用之select詳解

2021-07-08 15:51:08 字數 2562 閱讀 4901

io復用技術使得程式能夠同時監聽多個檔案描述符,這對提高程式的效能至關重要。

linux下實現io復用的系統呼叫主要有select、poll和epoll,本文主要介紹select,後兩個將在後續文章介紹。

盡量使select講解的簡單易懂,便於自己日後複習和有需要的新手朋友。

select系統呼叫的主要用途是:在指定的一段時間內,輪詢監聽使用者感興趣的檔案描述符,即使用者新增記錄到fd_set中的檔案描述符,當監聽到任何檔案描述符有可讀,可寫和異常事件發生時,就會返回。

輪詢:即一遍又一遍的迴圈監聽從0到我們記錄的這些檔案描述符中的最大值。

fd_set:是乙個結構體,這個結構體中僅包含乙個整型陣列,這個整型陣列的每個元素的每個位代表乙個檔案描述符,所以select能同時處理的檔案描述符的最大數量由這個陣列的總位數決定,這個最大值為標頭檔案中定義的乙個常量fd_setsize。

#include int select(int nfd, fd_set *readfd, fd_set *writefd, fd_set *exceptfd, struct timeval *timeout)

1)nfd 引數指定了被監聽的檔案描述符的總數,它通常是readfd,writefd,exceptfd這三個描述符集中的最大描述符編號加1,因為檔案描述符是從0開始計數的。

2)readfd,writefd,exceptfd分別指向可讀,可寫,異常事件對應的檔案描述符集合。當一開始使用select函式時,我們會在這三個描述符集合中記錄我們感興趣的檔案描述符,輪詢等待這些描述符有事件產生,select呼叫返回時,原先我們記錄的檔案描述符就消失,然後核心會把有可讀,可寫或異常事件發生的檔案描述符記錄在這三個描述符集合中。至於事件發生的判斷在文章後給出。

3)timeout引數用來設定select函式的超時時間,表示select願意等待多長時間。它是乙個timeval結構型別的指標:

struct timeval;
當timeout==null時:select會無限等待,直到所監聽的檔案描述符有事件發生或**捉到乙個訊號。

當timeout->tv_sec==0 && timeout->tv_usec==0時:select根本不等待,測試所有指定的描述符並立即返回。

當timeout->tv_sec!=0 || timeout->tv_usec!=0時:等待指定的時間。在指定時間內有事件發生或捕捉到訊號時會立即返回。

1)返回-1,表示出錯,比如在select超時時間內捕捉到乙個訊號。

2)返回0,表示超時時間到了,但沒有乙個描述符有事件發生。此時readfd,writefd,exceptfd三個描述符集會被核心置0。

3)返回值大於0,表示有事件發生的描述符總數,如果乙個檔案描述符同時發生了讀寫事件,則會對其計數兩次。

由於對fd_set結構體裡陣列的每一位的操作過於麻煩,所以linux定義了一系列巨集來訪問修改fd_set中的位:

#include fd_zero(fd_set *fdset);               //清除fdset的所有位

fd_set(int fd, fd_set *fdset); //設定fdset的位fd

fd_clr(int fd, fd_set *fdset); //清除fdset的位fd

fd_isset(int fd, fd_set *fdset); //測試fdset的位fd是否被設定

主要討論網路程式設計中的事件就緒條件

1)核心接收緩衝區中的位元組數大於等於其低水位標記,該低水位標記由socket選項so_rcvlowat選項來設定。此時我們可以無阻塞的讀到資料,讀操作返回的位元組數大於0。

2)通訊對方關閉了連線。此時讀操作返回0。

3)服務端監聽socket檔案描述符上有新的連線請求。

4)socket上有未處理的錯誤。此時我們可以使用getsockopt來讀取和清除該錯誤。

1)核心傳送緩衝區中的空閒位元組數大於等於其低水位標記,該低水位標記由socket選項so_sndlowat選項來設定。此時我們可以無阻塞的寫資料,寫操作返回的位元組數大於0。

2)socket的寫操作被關閉。對寫操作被關閉的socket執行寫操作會觸發乙個sigpipe訊號。

3)socket使用非阻塞connect連線成功或者失敗(超時)之後。

4)socket上有未處理的錯誤。此時我們可以使用getsockopt來讀取和清除該錯誤。

#include #include #include #include int main()

} return 0;

}

這個例子的作用就是,監聽標準輸入上的可讀事件,當我們在鍵盤上輸入資料時,就會觸發可讀事件,select就會返回,核心會清空fdset描述符集,然後在fdset描述符集合中設定有事件發生的描述符,即標準輸入描述符0,接著用fd_isset判斷檔案描述符0是否在fdset中被設定。在while迴圈中每次select前都要重新記錄fdset,因為每次select返回後,核心都會設定fdset描述符集。

Linux網路程式設計 I O復用之select詳解

解決程序或執行緒阻塞到某個 i o 系統呼叫而出現的技術,使程序不阻塞於某個特定的 i o 系統調 1.當客戶處理多個描述符 通常是互動式輸入 網路套接字 時,必須使用i o復用。2.tcp伺服器既要處理監聽套接字,又要處理已連線套接字,一般要使用i o復用。3.如果乙個伺服器既要處理tcp又要處理...

Linux網路程式設計 I O復用之poll函式

目前幾乎在所有的平台上支援,其良好跨平台支援也是它的乙個優點1.每次呼叫 select 都需要把 fd 集合從使用者態拷貝到核心態,這個開銷在 fd 很多時會很大,同時每次呼叫 select 都需要在核心遍歷傳遞進來的所有 fd,這個開銷在 fd 很多時也很大。2.單個程序能夠監視的檔案描述符的數量...

Linux網路程式設計 I O復用之poll函式

小哥整理的不錯,對一些基礎的東西總結的比較全面。一 回顧前面的select select優點 目前幾乎在所有的平台上支援,其良好跨平台支援也是它的乙個優點 select缺點 1.每次呼叫 select 都需要把 fd 集合從使用者態拷貝到核心態,這個開銷在 fd 很多時會很大,同時每次呼叫 sele...