linux中select函式的使用

2021-07-30 12:56:09 字數 4340 閱讀 1705

linux中select函式的使用

select在socket程式設計中還是比較重要的,可是對於初學socket的人來說都不太愛用select寫程式,他們只是習慣寫諸如connect、accept、recv或recvfrom這樣的阻塞程式(所謂阻塞方式block,顧名思義,就是程序或是執行緒執行到這些函式時必須等待某個事件的發生,如果事件沒有發生,程序或執行緒就被阻塞,函式不能立即返回)。可是使用select就可以完成非阻塞(所謂非阻塞方式non-block,就是程序或執行緒執行此函式時不必非要等待事件的發生,一旦執行肯定返回,以返回值的不同來反映函式的執**況,如果事件發生則與阻塞方式相同,若事件沒有發生則返回乙個**來告知事件未發生,而程序或執行緒繼續執行,所以效率較高)方式工作的程式,它能夠監視我們需要監視的檔案描述符的變化情況——讀寫或是異常。下面詳細介紹一下!  

select的函式格式(我所說的是unix系統下的伯克利socket程式設計,和windows下的有區別,一會兒說明):  

int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);  

先說明兩個結構體:  

第一,struct fd_set可以理解為乙個集合,這個集合中存放的是檔案描述符(file descriptor),即檔案控制代碼,這可以是我們所說的普通意義的檔案,當然unix下任何裝置、管道、fifo等都是檔案形式,全部包括在內,所以毫無疑問乙個socket就是乙個檔案,socket控制代碼就是乙個檔案描述符。fd_set集合可以通過一些巨集由人為來操作,比如清空集合fd_zero(fd_set *),將乙個給定的檔案描述符加入集合之中fd_set(int ,fd_set *),將乙個給定的檔案描述符從集合中刪除fd_clr(int ,fd_set*),檢查集合中指定的檔案描述符是否可以讀寫fd_isset(int ,fd_set* )。一會兒舉例說明。  

第二,struct timeval是乙個大家常用的結構,用來代表時間值,有兩個成員,乙個是秒數,另乙個是毫秒數。  

具體解釋select的引數:  

int maxfdp是乙個整數值,是指集合中所有檔案描述符的範圍,即所有檔案描述符的最大值加1,不能錯!在windows中這個引數的值無所謂,可以設定不正確。  

fd_set *readfds是指向fd_set結構的指標,這個集合中應該包括檔案描述符,我們是要監視這些檔案描述符的讀變化的,即我們關心是否可以從這些檔案中讀取資料了,如果這個集合中有乙個檔案可讀,select就會返回乙個大於0的值,表示有檔案可讀,如果沒有可讀的檔案,則根據timeout引數再判斷是否超時,

若超出timeout的時間,select返回0,若發生錯誤返回負值。可以傳入null值,表示不關心任何檔案的讀變化。  

fd_set *writefds是指向fd_set結構的指標,這個集合中應該包括檔案描述符,我們是要監視這些檔案描述符的寫變化的,即我們關心是否可以向這些檔案中寫入資料了,如果這個集合中有乙個檔案可寫,select就會返回乙個大於0的值,表示有檔案可寫,如果沒有可寫的檔案,則根據timeout引數再判斷是否超時,若超出timeout的時間,select返回0,若發生錯誤返回負值。可以傳入null值,表示不關心任何檔案的寫變化。  

fd_set *errorfds同上面兩個引數的意圖,用來監視檔案錯誤異常。  

struct timeval* timeout是select的超時時間,這個引數至關重要,它可以使select處於三種狀態,第一,若將null以形參傳入,即不傳入時間結構,就是將select置於阻塞狀態,一定等到監視檔案描述符集合中某個檔案描述符發生變化為止;第二,若將時間值設為0秒0毫秒,就變成乙個純粹的非阻塞函式,不管檔案描述符是否有變化,都立刻返回繼續執行,檔案無變化返回0,有變化返回乙個正值;第三,timeout的值大於0,這就是等待的超時時間,即select在timeout時間內阻塞,超時時間之內有事件到來就返回了,否則在超時後不管怎樣一定返回,返回值同上述。  

返回值:  

負值:select錯誤 正值:某些檔案可讀寫或出錯 0:等待超時,沒有可讀寫或錯誤的檔案  

在有了select後可以寫出像樣的網路程式來!舉個簡單的例子,就是從網路上接受資料寫入乙個檔案中。  

例子:  

main()  

; //select等待3秒,3秒輪詢,要非阻塞就置0  

char buffer[256]=; //256位元組的接收緩衝區  

while(1)  

// end if break;  

}// end switch  

}//end while  

}//end main  

select()的機制中提供一fd_set的資料結構,實際上是一long型別的陣列,  

每乙個陣列元素都能與一開啟的檔案控制代碼(不管是socket控制代碼,還是其他  

檔案或命名管道或裝置控制代碼)建立聯絡,建立聯絡的工作由程式設計師完成,  

當呼叫select()時,由核心根據io狀態修改fd_set的內容,由此來通知執  

行了select()的程序哪一socket或檔案可讀,下面具體解釋:  

#include  

#include  

#include  

int select(nfds, readfds, writefds, exceptfds, timeout)  

int nfds;  

fd_set *readfds, *writefds, *exceptfds;  

struct timeval *timeout;  

ndfs:select監視的檔案控制代碼數,視程序中開啟的檔案數而定,一般設為呢要監視各檔案  

中的最大檔案號加一。  

readfds:select監視的可讀檔案控制代碼集合。  

writefds: select監視的可寫檔案控制代碼集合。  

exceptfds:select監視的異常檔案控制代碼集合。  

timeout:本次select()的超時結束時間。(見/usr/sys/select.h,  

可精確至百萬分之一秒!)  

當readfds或writefds中映象的檔案可讀或可寫或超時,本次select()  

就結束返回。程式設計師利用一組系統提供的巨集在select()結束時便可判  

斷哪一檔案可讀或可寫。對socket程式設計特別有用的就是readfds。  

fd_zero(fd_set *fdset):清空fdset與所有檔案控制代碼的聯絡。  

fd_set(int fd, fd_set *fdset):建立檔案控制代碼fd與fdset的聯絡。  

fd_clr(int fd, fd_set *fdset):清除檔案控制代碼fd與fdset的聯絡。  

fd_isset(int fd, fdset *fdset):檢查fdset聯絡的檔案控制代碼fd是否  

可讀寫,>0表示可讀寫。  

(關於fd_set及相關巨集的定義見/usr/include/sys/types.h)  

這樣,你的socket只需在有東東讀的時候才讀入,大致如下:  

...  

int sockfd;  

fd_set fdr;  

struct timeval timeout = ..;  

...  

for(;;)  

}  }  

所以乙個fd_isset(sockfd)就相當通知了sockfd可讀。  

至於struct timeval在此的功能,請man select。不同的timeval設定  

使使select()表現出超時結束、無超時阻塞和輪詢三種特性。由於  

timeval可精確至百萬分之一秒,所以windows的settimer()根本不算  

什麼。你可以用select()做乙個超級時鐘。  

fd_accept的實現?依然如上,因為客戶方socket請求連線時,會傳送  

連線請求報文,此時select()當然會結束,fd_isset(sockfd)當然大  

於零,因為有報文可讀嘛!至於這方面的應用,主要在於服務方的父  

socket,你若不喜歡主動accept(),可改為如上機制來accept()。  

至於fd_close的實現及處理,頗費了一堆cpu處理時間,未完待續。  

--  

討論關於利用select()檢測對方socket關閉的問題:  

仍然是本地socket有東東可讀,因為對方socket關閉時,會發乙個關閉連線  

通知報文,會馬上被select()檢測到的。

linux中select 函式相關

select 的機制中提供一fd set的資料結構,實際上是一long型別的陣列,每乙個陣列元素都能與一開啟的檔案控制代碼 不管是socket控制代碼,還是其他 檔案或命名管道或裝置控制代碼 建立聯絡,建立聯絡的工作由程式設計師完成,當呼叫select 時,由核心根據io狀態修改fd set的內容,...

Linux中select函式的使用舉例

linux中select函式的使用例子 for sockaddr in include for socket functions include for fcntl include for select include include include include include include ...

Linux 網路程式設計中的 select 函式

我們這裡簡單的說下 select 的作用,並給出 select 的客戶端例項。我們知道 select 是io 多路復用的乙個最簡單支援,poll 和 epoll 是 select 的公升級版。我們通常會遇到這樣乙個問題 當客戶端阻塞在 fgets 等待客戶輸入的時候,伺服器端斷開連線。而客戶端卻不能...