日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET

發(fā)布時(shí)間:2023/12/20 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
從別人的博客中轉(zhuǎn)載過來了這一篇文章,經(jīng)過重新編輯排版之后展現(xiàn)于此,做一個(gè)知識(shí)點(diǎn)保存與學(xué)習(xí)。

????select函數(shù)用于在非阻塞中,當(dāng)一個(gè)套接字或一組套接字有信號(hào)時(shí)通知你,系統(tǒng)提供select函數(shù)來實(shí)現(xiàn)多路復(fù)用輸入/輸出模型,原型:
int select(int maxfd,fd_set *rdset,fd_set *wrset,fd_set *exset,struct timeval *timeout);

???所在的頭文件為:#include <sys/time.h> 和#include <unistd.h>

???先對(duì)函數(shù)中的參數(shù)做一個(gè)簡(jiǎn)單的介紹。參數(shù)maxfd是需要監(jiān)視的最大的文件描述符值+1;rdset,wrset,exset分別對(duì)應(yīng)于需要檢測(cè)的可讀文件描述符的集合,可寫文件描述符的集 合及異常文件描述符的集合。struct timeval結(jié)構(gòu)用于描述一段時(shí)間長(zhǎng)度,如果在這個(gè)時(shí)間內(nèi),需要監(jiān)視的描述符沒有事件發(fā)生則函數(shù)返回,返回值為0。?
????在這些參數(shù)中有一個(gè)類似于結(jié)構(gòu)體的東西,
fd_set,這是什么的名字,我們先來看看這個(gè)所具有的含義吧。這是一組文件描述字(fd)的集合,它用一位來表示一個(gè)fd,等等,文件描述字,熟悉吧,之前都把這個(gè)當(dāng)做一個(gè)文件的路徑保存的地方了,也就是當(dāng)做是一個(gè)文件的標(biāo)志哦,現(xiàn)不在做猜想了,看看下文是怎么介紹的吧。

????對(duì)于fd_set類型通過下面四個(gè)宏來操作:
????FD_ZERO(fd_set *fdset)?將指定的文件描述符集清空,在對(duì)文件描述符集合進(jìn)行設(shè)置前,必須對(duì)其進(jìn)行初始化,如果不清空,由于在系統(tǒng)分配內(nèi)存空間后,通常并不作清空處理,所以結(jié)果是不可知的。
????FD_SET(fd_set *fdset)?用于在文件描述符集合中增加一個(gè)新的文件描述符。
????FD_CLR(fd_set *fdset)?用于在文件描述符集合中刪除一個(gè)文件描述符。
????FD_ISSET(int fd,fd_set *fdset)?用于測(cè)試指定的文件描述符是否在該集合中。

????過去。。。。。。好長(zhǎng)一大段哦,為了保證大家的注意力,我決定將這一大段長(zhǎng)長(zhǎng)的對(duì)過去情況的介紹去掉,直接尋找正題,保持目標(biāo)的關(guān)注度啊。現(xiàn)在,UNIX系統(tǒng)通常會(huì)在頭文件<sys/select.h>中定義常量FD_SETSIZE,它是數(shù)據(jù)類型fd_set的描述字?jǐn)?shù)量,其值通常是1024,這樣就能表示<1024的fd。

????好了在研究了一番關(guān)于fd_set的信息之后,再回到對(duì)select函數(shù)的理解上來吧。

????功能:測(cè)試指定的fd可讀?可寫?有異常條件待處理?
????readset??用來檢查可讀性的一組文件描述字。
????writeset 用來檢查可寫性的一組文件描述字。
????exceptset用來檢查是否有異常條件出現(xiàn)的文件描述字。(注:不包括錯(cuò)誤)
????timeout??用于描述一段時(shí)間長(zhǎng)度,如果在這個(gè)時(shí)間內(nèi),需要監(jiān)視的描述符沒有事件發(fā)生則函數(shù)返回,返回值為0。

????對(duì)于select函數(shù)的功能簡(jiǎn)單的說就是對(duì)文件fd做一個(gè)測(cè)試。測(cè)試結(jié)果有三種可能:
????1.timeout=NULL(阻塞:select將一直被阻塞,直到某個(gè)文件描述符上發(fā)生了事件)
????2.timeout所指向的結(jié)構(gòu)設(shè)為非零時(shí)間(等待固定時(shí)間:如果在指定的時(shí)間段里有事件發(fā)生或者時(shí)間耗盡,函數(shù)均返回)
????3.timeout所指向的結(jié)構(gòu),時(shí)間設(shè)為0(非阻塞:僅檢測(cè)描述符集合的狀態(tài),然后立即返回,并不等待外部事件的發(fā)生)

?

????返回值:返回對(duì)應(yīng)位仍然為1的fd的總數(shù)。注意啦:只有那些可讀,可寫以及有異常條件待處理的fd位仍然為1。否則為0哦。舉個(gè)例子,比如recv(), 在沒有數(shù)據(jù)到來調(diào)用它的時(shí)候,你的線程將被阻塞,如果數(shù)據(jù)一直不來,你的線程就要阻塞很久.這樣顯然不好。所以采用select來查看套節(jié)字是否可讀(也就是是否有數(shù)據(jù)讀了) 。
步驟如下——
socket s;
.....
fd_set set;
while(1)
{
FD_ZERO(&set);//將你的套節(jié)字集合清空
FD_SET(s, &set);//加入你感興趣的套節(jié)字到集合,這里是一個(gè)讀數(shù)據(jù)的套節(jié)字s
select(0,&set,NULL,NULL,NULL);//檢查套節(jié)字是否可讀,
//很多情況下就是是否有數(shù)據(jù)(注意,只是說很多情況)
//這里select是否出錯(cuò)沒有寫
if(FD_ISSET(s, &set) //檢查s是否在這個(gè)集合里面,
{ //select將更新這個(gè)集合,把其中不可讀的套節(jié)字去掉
//只保留符合條件的套節(jié)字在這個(gè)集合里面
recv(s,...);
}
//do something here
}

????理解select模型的關(guān)鍵在于理解fd_set,為說明方便,取fd_set長(zhǎng)度為1字節(jié),fd_set中的每一bit可以對(duì)應(yīng)一個(gè)文件描述符fd。則1字節(jié)長(zhǎng)的fd_set最大可以對(duì)應(yīng)8個(gè)fd。
???(1)執(zhí)行fd_set set; FD_ZERO(&set);則set用位表示是0000,0000。
???(2)若fd=5,執(zhí)行FD_SET(fd,&set);后set變?yōu)?001,0000(第5位置為1)

???(3)若再加入fd=2,fd=1,則set變?yōu)?001,0011
???(4)執(zhí)行select(6,&set,0,0,0)阻塞等待
???(5)若fd=1,fd=2上都發(fā)生可讀事件,則select返回,此時(shí)set變?yōu)?000,0011。注意:沒有事件發(fā)生的fd=5被清空。


基于上面的討論,可以輕松得出select模型的特點(diǎn):
???(1)可監(jiān)控的文件描述符個(gè)數(shù)取決與sizeof(fd_set)的值。

???(2)可以有效突破select可監(jiān)控的文件描述符上限。
???(3)將fd加入select監(jiān)控集的同時(shí),還要再使用一個(gè)數(shù)據(jù)結(jié)構(gòu)array保存放到select監(jiān)控集中的fd,一是用于再select 返回后,array作為源數(shù)據(jù)和fd_set進(jìn)行FD_ISSET判斷。二是select返回后會(huì)把以前加入的但并無事件發(fā)生的fd清空,則每次開始 select前都要重新從array取得fd逐一加入(FD_ZERO最先),掃描array的同時(shí)取得fd最大值maxfd,用于select的第一個(gè) 參數(shù)。
???(4)可見select模型必須在select前循環(huán)array(加fd,取maxfd),select返回后循環(huán)array(FD_ISSET判斷是否有時(shí)間發(fā)生)。


使用select函數(shù)的過程一般是:
????先調(diào)用宏FD_ZERO將指定的fd_set清零,然后調(diào)用宏FD_SET將需要測(cè)試的fd加入fd_set,接著調(diào)用函數(shù)select測(cè)試fd_set中的所有fd,最后用宏FD_ISSET檢查某個(gè)fd在函數(shù)select調(diào)用后,相應(yīng)位是否仍然為1。

以下是一個(gè)測(cè)試單個(gè)文件描述字可讀性的例子:
int isready(int fd)
{
int rc;
fd_set fds;
struct tim tv;
FD_ZERO(&fds);
FD_SET(fd,&fds);
tv.tv_sec = tv.tv_usec = 0;
rc = select(fd+1, &fds, NULL, NULL, &tv);
if (rc < 0) //error
return -1;
return FD_ISSET(fd,&fds) ? 1 : 0;
}

總結(jié)

以上是生活随笔為你收集整理的select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。