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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

select函数及fd_set介绍

發(fā)布時間:2024/1/23 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 select函数及fd_set介绍 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1. select函數(shù)

1. 用途

? ? ? ?在編程的過程中,經(jīng)常會遇到許多阻塞的函數(shù),好像read和網(wǎng)絡編程時使用的recv, recvfrom函數(shù)都是阻塞的函數(shù),當函數(shù)不能成功執(zhí)行的時候,程序就會一直阻塞在這里,無法執(zhí)行下面的代碼。這時就需要用到非阻塞的編程方式,使用select函數(shù)就可以實現(xiàn)非阻塞編程。
? ? ? ?select函數(shù)是一個輪循函數(shù),循環(huán)詢問文件節(jié)點,可設置超時時間,超時時間到了就跳過代碼繼續(xù)往下執(zhí)行。

2. 大致原理

? ? ? ?select需要驅(qū)動程序的支持,驅(qū)動程序?qū)崿F(xiàn)fops內(nèi)的poll函數(shù)。select通過每個設備文件對應的poll函數(shù)提供的信息判斷當前是否有資源可用(如可讀或?qū)?,如果有的話則返回可用資源的文件描述符個數(shù),沒有的話則睡眠,等待有資源變?yōu)榭捎脮r再被喚醒繼續(xù)執(zhí)行。詳細的原理請看這里

3. 函數(shù)定義

??該函數(shù)聲明如下

int select(int nfds, fd_set *readset, fd_set *writeset, fe_set* exceptset,

struct timeval* timeout);

參數(shù):

? ? ?nfds? ? 需要檢查的文件描述字個數(shù)

? ? ?readset? ?用來檢查可讀性的一組文件描述字。

? ? ?writeset? ? 用來檢查可寫性的一組文件描述字。

? ? ?exceptset? 用來檢查是否有異常條件出現(xiàn)的文件描述字。(注:錯誤不包括在異常條件之內(nèi))

? ? ?timeout? ? 超時,填NULL為阻塞,填0為非阻塞,其他為一段超時時間

返回值:

? ? ?返回fd的總數(shù),錯誤時返回SOCKET_ERROR

2. fd_set結構體

? ? ?

上面select函數(shù)中需要用到兩個fd_set形參,這個結構體到底做什么用的呢

? ? ? ?fd_set其實這是一個數(shù)組的宏定義,實際上是一long類型的數(shù)組,每一個數(shù)組元素都能與一打開的文件句柄(socket、文件、管道、設備等)建立聯(lián)系,建立聯(lián)系的工作由程序員完成,當調(diào)用select()時,由內(nèi)核根據(jù)IO狀態(tài)修改fd_set的內(nèi)容,由此來通知執(zhí)行了select()的進程哪個句柄可讀。

? ? ? ?系統(tǒng)提供了FD_SET,?FD_CLR,?FD_ISSET,?FD_ZERO進行操作,聲明如下:

FD_SET(int fd, fd_set *fdset); //將fd加入set集合 FD_CLR(int fd, fd_set *fdset); //將fd從set集合中清除 FD_ISSET(int fd, fd_set *fdset); //檢測fd是否在set集合中,不在則返回0 FD_ZERO(fd_set *fdset); //將set清零使集合中不含任何fd

下面寫一段程序探究一下這幾個宏的工作:

#include <WINSOCK2.H>int main() {fd_set fdset;FD_ZERO(&fdset);FD_SET(1, &fdset);FD_SET(2, &fdset);FD_SET(3, &fdset);FD_SET(7, &fdset);int isset = FD_ISSET(3, &fdset);printf("isset = %d\n", isset);FD_CLR(3, &fdset);isset = FD_ISSET(3, &fdset);printf("isset = %d\n", isset);return 0; }

?當使用FD_SET添加完1、2、3、7后,fdset的值如下:

? ?然后經(jīng)過FD_CLR以后,fd_array[2]就被清除了,數(shù)組后面的數(shù)據(jù)一次往前提,即7被放到了fd_array[2]

? ?所以isset前后兩次打印的值分別為1和0

3. 小結

? ?select的結果會對fd_set造成影響。例如,對于一個監(jiān)聽的socket:

#include <WinSock2.h> #include <stdio.h> #pragma comment(lib,"WS2_32.lib") int main() {FD_SET ReadSet;FD_ZERO(&ReadSet);WSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData); //初始化SOCKET ListenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); //定義一個監(jiān)聽套接字//bind 等操作這里省略.... //......FD_SET(ListenSocket, &ReadSet); //將套接字加入ReadSet集合中int isset = FD_ISSET(ListenSocket, &ReadSet); //這里并沒有通過select對fd_set進行篩選 printf("Before select, isset = %d\n", isset); //所以這里打印結果為1 struct timeval tTime; tTime.tv_sec = 10; tTime.tv_usec = 0; select(0, &ReadSet, NULL, NULL, &tTime); //通過select篩選處于就緒狀態(tài)的fd //這時,剛才的ListenSocket并不在就緒狀態(tài)(沒有連接連入),那么就從ReadSet中去除它 isset = FD_ISSET(ListenSocket, &ReadSet); printf("After select, isset = %d\n", isset); //所以這里打印的結果為0 system("pause"); return 0; }

所以可以使用select以及fd的操作來完成異步的網(wǎng)絡消息處理,具體的實現(xiàn)請看這里的例子

總結

以上是生活随笔為你收集整理的select函数及fd_set介绍的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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