三種I O多路復用機制學習記錄 select 2

2021-10-24 02:22:32 字數 2880 閱讀 2198

現在開始學習三種i/o多路復用機制的第二種——select,上篇文章也講到,由於我水過了作業系統的上機,因此要不停的補坑,在校的各位未來程式設計師們,上課要好好學習,**一定要自己敲。select我真的有點不記得了,但是學過go語言的通道後,一定也會知道go語言中也有乙個select,這兩個select功能會不會有相同之處呢,讓我們(其實只有我)拭目以待。

int

select

(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,

struct timeval *timeout)

;

先看一下select的各個入參:

maxfdp:所有檔案描述符中最大的檔案描述符+1;

readfds:fdset指標,fd_set是乙個存放檔案描述符的集合,這個結構可以定義一些巨集來實現檔案描述符和集合之間的聯絡(清空和設定,可用不可用等) ,該引數是可讀檔案描述符集合

writefds:可寫檔案描述符集合

errorfds:異常檔案描述符集合

timeout:是乙個timeval結構體指標,timeval的具體結構如下:

struct timeval
當timeout == null時,select為阻塞模式,必須等到乙個檔案描述符發生變化才能返回繼續執行;

當timeout.tv_sec == 0 && timeout.tv_usec == 0時,不管有沒有檔案描述符發生變化都要返回;

當timeout的總時間》0時,超時時間內有事件變化就會返回;

select函式的返回值和poll是類似的:

返回值》0:監視的檔案描述符發生了變化;

返回值=0:在超時時間內,沒有任何檔案描述符發生變化;

返回值<0:發生錯誤。

看完這個函式,我們發現select和go語言中的select還是有相似的地方的,go語言中的select中監視的是通道中的訊息。

通過poll和select兩個函式原型就會發現兩者的不同,現在提出我的疑問:

1.poll傳入的檔案描述符的陣列,並傳入陣列的大小,而select傳入的所有檔案描述符中最大的描述符+1,select為什麼這樣設計?傳入明確的檔案描述符不是最簡便嗎?

2.poll函式可以說是以事件來驅動的,select怎麼來監控讀寫和異常的?因為看到select函式中傳入了三種檔案描述符集合。

針對這兩個問題,我們去找一下答案吧。

關於問題1,下面這篇部落格寫了一部分:

簡單來講就是在linux下,select會監控0-maxfdp-1所有的檔案描述符;但是select為什麼要這樣設計呢?為什麼不只監視需要監視的檔案描述符呢,監視所有的檔案描述符沒有必要呀,還是處於疑問當中,如果各位在看這篇部落格也有同樣的疑問並且知道答案了麻煩也告知我一聲。

另外這樣設計我猜測和fd_set結構應該有一定關係,問題2也必須通過這個結構來解釋了。我們來具體看一下fd_set:

select.h中定義了一些巨集來實現了檔案描述符和這個檔案描述符的聯絡:

#include

intfd_zero

(fd_set *fdset)

;//將乙個fd_set型別變數的所有位都設定為0。

intfd_clr

(int fd,fd_set *fdset)

;//將變數的某個位清零

intfd_set

(int fd,fd_set *fdset)

;//將變數的某一位置零

intfd_isset

(int fd,fd_set *fdset)

;//測試某個位是否被置位。

從字面上應該很容易理解這些巨集的功能,fdset中的每一bit則代表乙個檔案描述符。

舉乙個小例子:

fd_zero(fdset) fdset為0000 0000

fd_set(3,fdset) fdset為 0000 0100

是不是很好理解呀,系統在後台監控各個檔案描述符的變化,最終修改fd_set的值,從而監控讀寫和異常。

另外看了一些資料,發現我們在使用select函式時,如果要同時監控讀寫和異常還必須另外建立三個fd陣列,用於存放使用者真正要監控的fd,如此一來,整個select的函式的用法可以如下(我接下來要寫乙份偽**了):

//監控可讀的檔案描述符

int rfds[2]

=;fd_set rfdset;

fd_zero

(&rfdset)

;fd_set

(rfds[0]

,&rfdset)

;//你們肯定要問為什麼要做兩次置0操作,我也很疑惑

fd_set

(reds[1]

,&rfdset)

;int ret;

ret =

select(5

,&rfdset,0,

0,0)

//監控讀檔案描述符集合的變化;if(

fd_isset

(rfds[

0],&rfdset)if(

fd_isset

(rfds[1]

,&rfdset)

大概就是上面的用法,但是在寫偽**時想到乙個奇怪的問題:系統中可以執行很多個select嗎?如果兩個select函式同時都監控同乙個檔案描述符,我們做fd_set應該是沒有影響的吧,應該是的,每個檔案描述符集合都是不一樣的,我突然又想通了。

我疑惑的那兩個問題很明顯的暴露了select的兩個明顯缺點:1.select會監控我們不想關注的檔案描述符,所以效率一定會有所降低,另外使用起來也不如poll方便。

2.監控的fd是有限,監控的數量會和當前的記憶體有關。

為了應付面試,暫時就學到這了,後續希望能接觸相關的任務,從而深入學習。

三種I O多路復用機制學習記錄 poll 1

fdset pollfd結構體陣列,pollfd的結構體定義如下 include struct pollfd單看這個結構是不是有點懵,但是如果我們知道這些事件型別分為可讀 可寫 異常這三種,或許好理解一點,這個結構體指定了我們感興趣的檔案描述符上發生的可讀可寫和異常事件 現在或許還是很懵,我們繼續 ...

IO模型 io多路復用(三)

兩者相互比較 1 如果只有乙個使用者連線server端,多路復用io還不如阻塞io效率高 2 相比阻塞io,多路復用io中間多了個反饋機制 3 多路復用io的 可以同時監控socket 多個socket物件coon1 coon2.recv 4 多路復用io可以識別有人連線某個coon3,然後告知有c...

多路復用IO 學習筆記

1 阻塞io,常用的scanf printf read write cout cin 2 非阻塞io,recv send和qt中read write 3 多路復用io 4 訊號驅動io 5 非同步io在不建立新的程序和執行緒的情況下監控多個檔案描述符,多應用於網路程式設計時乙個服務端程式為多個客戶端...