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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

select机制

發(fā)布時間:2025/3/21 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 select机制 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?

背景知識分析:

?1. fd_set 結(jié)構(gòu)體

? fd_set是文件句柄的集合。???
????
?? FD_ZERO??? 清空這個集合;???
?? FD_SET 往這個集合里面加入一個文件句柄;???
?? FD_ISSET????? 查看某一個文件句柄是否被設(shè)置了;

?? 'fd_set') 是一組文件描述符(fd)的集合。由于fd_set類型的長度在不同平臺上不同,因此應(yīng)該用一組標(biāo)準(zhǔn)的宏定義來處理此類變量:??

?? fd_set set;??????

?? FD_ZERO(&set);??????? /* 將set清零 */????

?? FD_SET(fd, &set);???? /* 將fd加入set */???

?? FD_CLR(fd, &set);???? /* 將fd從set中清除 */????

?? FD_ISSET(fd, &set);?? /* 判斷fd是否處于可用狀態(tài) 是為true */??

2使用介紹:

[cpp]?view plaincopy
  • <font?face="Verdana">fd_set?rdfds;?/*?先申明一個?fd_set?集合來保存我們要檢測的?socket句柄?*/??
  • struct?timeval?tv;?/*?申明一個時間變量來保存時間?*/??
  • int?ret;?/*?保存返回值?*/??
  • FD_ZERO(&rdfds);?/*?用select函數(shù)之前先把集合清零?*/??
  • FD_SET(socket,?&rdfds);?/*?把要檢測的句柄socket加入到集合里?*/??
  • tv.tv_sec?=?1;??
  • tv.tv_usec?=?500;?/*?設(shè)置select等待的最大時間為1秒加500毫秒?*/??
  • ret?=?select(socket?+?1,?&rdfds,?NULL,?NULL,?&tv);?/*?檢測我們上面設(shè)置到集合rdfds里的句柄是否有可讀信息?*/??
  • if(ret?<?0)?perror("select");/*?這說明select函數(shù)出錯?*/??
  • else?if(ret?==?0)?printf("超時/n");?/*?說明在我們設(shè)定的時間值1秒加500毫秒的時間內(nèi),socket的狀態(tài)沒有發(fā)生變化?*/??
  • else?{?/*?說明等待時間還未到1秒加500毫秒,socket的狀態(tài)發(fā)生了變化?*/??
  • ????printf("ret=%d/n",?ret);?/*?ret這個返回值記錄了發(fā)生狀態(tài)變化的句柄的數(shù)目,由于我們只監(jiān)視了socket這一個句柄,所以這里一定ret=1,如果同時有多個句柄發(fā)生變化返回的就是句柄的總和了?*/??
  • ????/*?這里我們就應(yīng)該從socket這個句柄里讀取數(shù)據(jù)了,因為select函數(shù)已經(jīng)告訴我們這個句柄里有數(shù)據(jù)可讀?*/??
  • ????if(FD_ISSET(socket,?&rdfds))?{?/*?先判斷一下socket這外被監(jiān)視的句柄是否真的變成可讀的了?*/??
  • ????????/*?讀取socket句柄里的數(shù)據(jù)?*/??
  • ????????recv(...);??
  • ????}??
  • }??
  • ?</font>??
  • 注意select函數(shù)的第一個參數(shù),是所有加入集合的句柄值的最大那個值還要加1。比如我們創(chuàng)建了3個句柄:

    [cpp]?view plaincopy
  • int?sa,?sb,?sc;??
  • sa?=?socket(...);?/*?分別創(chuàng)建3個句柄并連接到服務(wù)器上?*/??
  • connect(sa,...);??
  • sb?=?socket(...);??
  • connect(sb,...);??
  • sc?=?socket(...);??
  • connect(sc,...);??
  • FD_SET(sa,?&rdfds);/*?分別把3個句柄加入讀監(jiān)視集合里去?*/??
  • FD_SET(sb,?&rdfds);??
  • FD_SET(sc,?&rdfds);??
  • ???
  • 在使用select函數(shù)之前,一定要找到3個句柄中的最大值是哪個,我們一般定義一個變量來保存最大值,取得最大socket值如下:

    [cpp]?view plaincopy
  • int?maxfd?=?0;??
  • if(sa?>?maxfd)?maxfd?=?sa;??
  • if(sb?>?maxfd)?maxfd?=?sb;??
  • if(sc?>?maxfd)?maxfd?=?sc;??
  • 然后調(diào)用select函數(shù):

    [cpp]?view plaincopy
  • ret?=?select(maxfd?+?1,?&rdfds,?NULL,?NULL,?&tv);?/*?注意是最大值還要加1?*/??
  • ?

    3 關(guān)于 Select 的 FD_SETSIZE

    ?

    nt select(int n, fd_set *rd_fds, fd_set *wr_fds, fd_set *ex_fds, struct timeval *timeout);
    Select 用到了fd_set結(jié)構(gòu),從man page里可以知道fd_set能容納的句柄和FD_SETSIZE相關(guān)。實際上fd_set在*nix下是一個bit標(biāo)志數(shù)組,每個bit表示對應(yīng)下標(biāo) 的fd是不是在fd_set中。fd_set只能容納編號小于 FD_SETSIZE的那些句柄。
    FD_SETSIZE默認(rèn)是1024,如果向 fd_set里放入過大的句柄,數(shù)組越界以后程序就會垮掉。系統(tǒng)默認(rèn)限制了一個進程最大的句柄號不超過1024,但是可以通過ulimit -n命令/setrlimit函數(shù)來擴大這一限制。如果不幸一個程序在FD_SETSIZE=1024的環(huán)境下編譯,運行時又遇到ulimit n > 1024的,那就只有祈求上帝保佑不會垮掉了。

    通過上述說明,可以看到如果連接很多的話,建議還是使用epoll來解決這個問題。

    4 select 機制的優(yōu)勢

    為什么會出現(xiàn)select模型?

    先看一下下面的這句代碼:
    int iResult = recv(s, buffer,1024);
    這是用來接收數(shù)據(jù)的,在默認(rèn)的阻塞模式下的套接字里,recv會阻塞在那里,直到套接字連接上有數(shù)據(jù)可讀,把數(shù)據(jù)讀到buffer里后recv函數(shù)才會返 回,不然就會一直阻塞在那里。在單線程的程序里出現(xiàn)這種情況會導(dǎo)致主線程(單線程程序里只有一個默認(rèn)的主線程)被阻塞,這樣整個程序被鎖死在這里,如果永 遠沒數(shù)據(jù)發(fā)送過來,那么程序就會被永遠鎖死。這個問題可以用多線程解決,但是在有多個套接字連接的情況下,這不是一個好的選擇,擴展性很差。
    再看代碼:
    int iResult = ioctlsocket(s, FIOBIO, (unsigned long *)&ul);
    iResult = recv(s, buffer,1024);

    這一次recv的調(diào)用不管套接字連接上有沒有數(shù)據(jù)可以接收都會馬上返回。原因就在于我們用ioctlsocket把套接字設(shè)置為非阻塞模式了。不過 你跟蹤 一下就會發(fā)現(xiàn),在沒有數(shù)據(jù)的情況下,recv確實是馬上返回了,但是也返回了一個錯誤:WSAEWOULDBLOCK,意思就是請求的操作沒有成功完成。 看到這里很多人可能會說,那么就重復(fù)調(diào)用recv并檢查返回值,直到成功為止,但是這樣做效率很成問題,開銷太大。

    select模型的出現(xiàn)就是為了解決上述問題。

    select模型的關(guān)鍵是使用一種有序的方式,對多個套接字進行統(tǒng)一管理與調(diào)度?。

    看核心代碼:(這里只給出服務(wù)端的)

    while ( 1 )
    {
    // 初始化fdset
    FD_ZERO( &fdsRead );

    // 將server套接字添加到可讀集合中
    FD_SET( sockServer, &fdsRead );

    // 調(diào)用select
    select( 0, &fdsRead, NULL, NULL, &tv );

    // 判斷server套接字的狀態(tài),如果套接字還在可讀集合中,
    // 說明有數(shù)據(jù)可以讀入,則建立套接字可以成功
    if ( FD_ISSET( sockServer, &fdsRead ) )
    {
    sockAccept = accept( sockServer, (sockaddr*)&addr, &nLen );
    // 有數(shù)據(jù)可讀,進行相關(guān)處理
    }

    ?

    ?


    總結(jié)

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

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