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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

linux网络编程--select/poll/epoll 详解

發(fā)布時(shí)間:2024/2/28 linux 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux网络编程--select/poll/epoll 详解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

參考鏈接

epoll函數(shù)

close

epoll event

EL/LT

ET Edge Trigger 邊沿觸發(fā)工作模式

LT Level Trigger 水平觸發(fā)工作模式

epoll 源碼解析

一道騰訊后臺(tái)開(kāi)發(fā)面試題

ET/LT 比較

epoll 優(yōu)點(diǎn)

epoll 源碼解讀

select()

select()簡(jiǎn)介

為什么需要select()?

select()函數(shù)

select 缺點(diǎn)

select() 文件描述符上限

poll()

fdarray

nfds

timeout

poll() 文件描述符上限

poll()/select()的區(qū)別


參考鏈接

  • epoll簡(jiǎn)介及觸發(fā)模式(accept、read、send)
  • epoll內(nèi)核源碼詳解+自己總結(jié)的流程
  • linux man page
  • epoll函數(shù)

    注意: epoll不屬于任何namespace。

    #include <sys/epoll.h>int epoll_create(int size); // return epollfd, 失敗return -1/* op: EPOLL_CTL_ADD EPOLL_CTL_MOD EPOLL_CTL_DEL 如果是delete的話(huà), epoll_ctl的最后一個(gè)參數(shù)event可以是NULL */ int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); // 成功return0, 失敗return -1 int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout); // 成功return nready. 失敗return -1//epoll_event /* 其實(shí)這個(gè)epoll_data只是給用戶(hù)自行使用的,epoll不關(guān)心里面的內(nèi)容。 這個(gè)dta回隨著epoll_data 返回的epoll_event一并返回 */ typedef union epoll_data {void *ptr;int fd;uint32_t u32;uint64_t u64; } epoll_data_t;struct epoll_event {uint32_t events; /* Epoll events */epoll_data_t data; /* User data variable */ };

    close

    其實(shí)在外面關(guān)閉一個(gè)fd之后,就可以不用再在epoll list里面刪除了,但是為了安全起見(jiàn),還是用EPOLL_CTL_DEL刪掉吧。詳情可以看 epoll(7) man page FAQ。

    epoll event

  • EPOLLIN :表示對(duì)應(yīng)的文件描述符可以讀(包括對(duì)端SOCKET正常關(guān)閉);
  • EPOLLOUT:表示對(duì)應(yīng)的文件描述符可以寫(xiě);
  • EPOLLPRI:表示對(duì)應(yīng)的文件描述符有緊急的數(shù)據(jù)可讀(這里應(yīng)該表示有帶外數(shù)據(jù)到來(lái));
  • EPOLLERR:表示對(duì)應(yīng)的文件描述符發(fā)生錯(cuò)誤;
  • EPOLLHUP:表示對(duì)應(yīng)的文件描述符被掛斷;
  • EPOLLET: 將EPOLL設(shè)為邊緣觸發(fā)(Edge Triggered)模式,這是相對(duì)于水平觸發(fā)(Level Triggered)來(lái)說(shuō)的。
  • EPOLLONESHOT:只監(jiān)聽(tīng)一次事件,當(dāng)監(jiān)聽(tīng)完這次事件之后,如果還需要繼續(xù)監(jiān)聽(tīng)這個(gè)socket的話(huà),需要再次把這個(gè)socket加入到EPOLL隊(duì)列里
  • EL/LT

    有關(guān)ET/LT 阻塞/非阻塞的操作,網(wǎng)絡(luò)上基本都是錯(cuò)的,只要你安排的好,既可以用阻塞,也可以用非阻塞。(linux man page上也讓你用阻塞)

    ET Edge Trigger 邊沿觸發(fā)工作模式

  • 必須使用非阻塞 工作模式,因?yàn)樵谘h(huán)調(diào)用epoll_wait的時(shí)候,有可能某個(gè)句柄已知會(huì)ready, 如果用阻塞操作,會(huì)導(dǎo)致一個(gè)文件句柄的阻塞操作把多個(gè)文件描述符餓死。
  • 基于非阻塞文件句柄
  • 只有當(dāng)read(2)或者write(2)返回EAGAIN時(shí)才需要掛起,等待(退出read/write返回epoll_wait)。但這并不是說(shuō)每次read()時(shí)都需要循環(huán)讀,直到讀到產(chǎn)生一個(gè)EAGAIN才認(rèn)為此次事件處理完成,當(dāng)read()返回的讀到的數(shù)據(jù)長(zhǎng)度小于請(qǐng)求的數(shù)據(jù)長(zhǎng)度時(shí)(即小于sizeof(buf)),就可以確定此時(shí)緩沖中已沒(méi)有數(shù)據(jù)了,也就可以認(rèn)為此事讀事件已處理完成。
  • 阻塞IO的事件處理原則:
  • recv() > 0:(并且小于請(qǐng)求的數(shù)據(jù)長(zhǎng)度sizeof(buf)), 表示接收數(shù)據(jù)完畢,返回值即是接收到的字節(jié)數(shù)。
  • recv() == 0: 表示鏈接已經(jīng)正常斷開(kāi),這個(gè)時(shí)候就可以把fd關(guān)掉,從epoll里面移除了
  • recv() < 0 && errno == EAGAIN: 表示recv操作還未完成
  • recv() < 0 && errno != EAGAIN: 表示操作遇到系統(tǒng)errno
  • 邊緣觸發(fā)但是這種模式下在讀數(shù)據(jù)的時(shí)候一定要注意,因?yàn)槿绻淮慰蓪?xiě)事件我們沒(méi)有把數(shù)據(jù)讀完,如果沒(méi)有讀完,在socket沒(méi)有新的數(shù)據(jù)可讀時(shí)epoll就不回返回了,只有在新的數(shù)據(jù)到來(lái)時(shí),我們才能讀取到上次沒(méi)有讀完的數(shù)據(jù)。最差的情況是client在發(fā)送的n個(gè)byte之后已經(jīng)關(guān)閉了,但是epoll由于接收緩沖區(qū)沒(méi)有清空,這個(gè)fd在服務(wù)端并不會(huì)關(guān)掉。
  • 使用ET模式,就算接收緩沖區(qū)里的數(shù)據(jù)沒(méi)有讀完,如果再接收到新的數(shù)據(jù), epoll_wait 還是會(huì)觸發(fā)可讀事件的。
  • 設(shè)置為EPOLLET之后仍然會(huì)對(duì)同一事件多次觸發(fā)的原因:
  • 接收緩沖區(qū)過(guò)小,無(wú)法容納所有發(fā)送過(guò)來(lái)的數(shù)據(jù)(這個(gè)我自己沒(méi)有復(fù)現(xiàn)出來(lái))
  • 用EPOLL_CTL_MOD更改了epollevent,會(huì)重置之前的觸發(fā)
  • LT Level Trigger 水平觸發(fā)工作模式

  • poll(), select() 都是水平觸發(fā)
  • 如果我們用水平觸發(fā)不用擔(dān)心數(shù)據(jù)有沒(méi)有讀完因?yàn)橄麓蝒poll返回時(shí),沒(méi)有讀完的socket依然會(huì)被返回
  • 但是要注意這種模式下的寫(xiě)事件,因?yàn)槭撬接|發(fā),每次socket可寫(xiě)時(shí)epoll都會(huì)返回,當(dāng)我們寫(xiě)的數(shù)據(jù)包過(guò)大時(shí),一次寫(xiě)不完,要多次才能寫(xiě)完或者每次socket寫(xiě)都寫(xiě)一個(gè)很小的數(shù)據(jù)包時(shí),每次寫(xiě)都會(huì)被epoll檢測(cè)到,因此長(zhǎng)期關(guān)注socket寫(xiě)事件會(huì)無(wú)故cpu消耗過(guò)大甚至導(dǎo)致cpu跑滿(mǎn),所以在水平觸發(fā)模式下我們一般不關(guān)注socket可寫(xiě)事件而是通過(guò)調(diào)用socket write或者send api函數(shù)來(lái)寫(xiě)socket
  • 但是如果使用LT模式,每次讀事件只要調(diào)用一次recv()就可以了。不用像ET一樣反復(fù)調(diào)用recv()直到返回EAGAIN,對(duì)于追求低延遲的系統(tǒng)調(diào)用來(lái)說(shuō),這么做是搞笑的,并且也不用擔(dān)心因?yàn)槟硞€(gè)連接上數(shù)據(jù)量過(guò)大導(dǎo)致影響其他連接處理消息。
  • 我們可以看到這種模式在效率上是沒(méi)有邊緣觸發(fā)高的,因?yàn)槊總€(gè)socket讀或者寫(xiě)可能被返回兩次甚至多次
  • epoll 源碼解析

    https://blog.csdn.net/wangyin159/article/details/48895287

    epoll_wait

  • 檢查MAXEXENT參數(shù)
  • 用access_ok() 檢查event指針是否可寫(xiě),如果這個(gè)指針是空指針或者指向內(nèi)核態(tài)的指針,那么會(huì)設(shè)置errno EFAULT。
  • Just because a pointer was supplied by userspace doesn't mean that it's definitely a userspace pointer - in many cases "kernel pointer" simply means that it's pointing within a particular region of the virtual address space.https://stackoverflow.com/questions/12357752/what-is-the-point-of-using-the-linux-macro-access-ok
  • 獲取epfd對(duì)應(yīng)的eventpoll文件實(shí)例,如果取不到,errno:EBADF
  • 檢查eventpoll文件是不是真的是一個(gè)epoll文件, 如果不是說(shuō)值errno EINVAL
  • 其實(shí)epoll_wait 中如果出錯(cuò)了,那么基本上應(yīng)該是程序本身的問(wèn)題,比如陷入死循環(huán)之類(lèi)
  • 調(diào)用ep_epoll函數(shù),這個(gè)函數(shù)在做一些配置之后就會(huì)主動(dòng)讓出處理器,進(jìn)入睡眠狀態(tài),等待文件就緒(回調(diào)函數(shù)喚醒本進(jìn)程)或者超時(shí)或者信號(hào)中斷
    • 缺省的工作模式

    一道騰訊后臺(tái)開(kāi)發(fā)面試題

    Q:使用Linux?epoll模型,水平(LT)觸發(fā)模式,當(dāng)socket可寫(xiě)時(shí),會(huì)不停的觸發(fā)socket可寫(xiě)的事件,如何處理?

  • 第一種最普遍的方式:
    • 需要向socket寫(xiě)數(shù)據(jù)的時(shí)候才把socket加入epoll,等待可寫(xiě)事件。接受到可寫(xiě)事件后,調(diào)用write或者send發(fā)送數(shù)據(jù)。當(dāng)所有數(shù)據(jù)都寫(xiě)完后,把socket移出epoll(用EPOLLONESHOT也行)。
    • 這種方式的缺點(diǎn)是,即使發(fā)送很少的數(shù)據(jù),也要把socket加入epoll,寫(xiě)完后在移出epoll,有一定操作代價(jià)。
  • 一種改進(jìn)的方式:
    • 開(kāi)始不把socket加入epoll,需要向socket寫(xiě)數(shù)據(jù)的時(shí)候,直接調(diào)用write或者send發(fā)送數(shù)據(jù)。如果返回EAGAIN(緩沖區(qū)滿(mǎn)了,后面還需要繼續(xù)發(fā)),把socket加入epoll,在epoll的驅(qū)動(dòng)下寫(xiě)數(shù)據(jù),全部數(shù)據(jù)發(fā)送完畢后,再移出epoll。
    • 這種方式的優(yōu)點(diǎn)是:數(shù)據(jù)不多的時(shí)候可以避免epoll的事件處理,提高效率。
  • ET/LT 比較

  • 因?yàn)镋T要基于非阻塞IO, LT在讀寫(xiě)的時(shí)候不必等待EAGAIN的出現(xiàn),可以節(jié)省系統(tǒng)調(diào)用次數(shù),降低延遲
  • ET可以保證每次只觸發(fā)一個(gè)
  • epoll 優(yōu)點(diǎn)

  • 對(duì)應(yīng)select()的缺點(diǎn), epoll都有解決的方法

  • 每次調(diào)用select,都需要把fd集合從用戶(hù)態(tài)拷貝到內(nèi)核態(tài),這個(gè)開(kāi)銷(xiāo)在fd很多時(shí)會(huì)很大
    • 使用epoll_ctl()函數(shù),只有在注冊(cè)、修改、刪除的時(shí)候才會(huì)對(duì)內(nèi)核進(jìn)行操作。
  • 同時(shí)每次調(diào)用select都需要在內(nèi)核遍歷傳遞進(jìn)來(lái)的所有fd,這個(gè)開(kāi)銷(xiāo)在fd很多時(shí)也很大
    • epoll的解決方案不像select或poll一樣每次都把current輪流加入fd對(duì)應(yīng)的設(shè)備等待隊(duì)列中,而只在epoll_ctl時(shí)把current掛一遍(這一遍必不可少)并為每個(gè)fd指定一個(gè)回調(diào)函數(shù),當(dāng)設(shè)備就緒,喚醒等待隊(duì)列上的等待者時(shí),就會(huì)調(diào)用這個(gè)回調(diào)函數(shù),而這個(gè)回調(diào)函數(shù)會(huì)把就緒的fd加入一個(gè)就緒鏈表)。epoll_wait的工作實(shí)際上就是在這個(gè)就緒鏈表中查看有沒(méi)有就緒的fd(利用schedule_timeout()實(shí)現(xiàn)睡一會(huì),判斷一會(huì)的效果,和select實(shí)現(xiàn)中的第7步是類(lèi)似的)
  • select支持的文件描述符數(shù)量太小了,默認(rèn)是1024
    • epoll沒(méi)有這個(gè)限制,它所支持的FD上限是最大可以打開(kāi)文件的數(shù)目,這個(gè)數(shù)字一般遠(yuǎn)大于2048,舉個(gè)例子,我的1GB內(nèi)存阿里云ECS是999999,具體數(shù)目可以cat /proc/sys/fs/file-max察看,一般來(lái)說(shuō)這個(gè)數(shù)目和系統(tǒng)內(nèi)存關(guān)系很大。
  • poll每次返回整個(gè)文件描述符數(shù)組, 用戶(hù)需要遍歷數(shù)組已找到哪些文件描述符上有IO事件。 而epoll_wait(2)返回的是活動(dòng)fd的列表,需要遍歷的數(shù)組通常會(huì)小很多,在并發(fā)連接數(shù)較大而活動(dòng)連接比例不高時(shí),epoll(4)比epoll(2)更高效。

  • epoll 源碼解讀

    當(dāng)某一進(jìn)程調(diào)用epoll_create方法時(shí),Linux內(nèi)核會(huì)創(chuàng)建一個(gè)eventpoll結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體中有兩個(gè)成員與epoll的使用方式密切相關(guān)。eventpoll結(jié)構(gòu)體如下所示:

    struct eventpoll{..../*紅黑樹(shù)的根節(jié)點(diǎn),這顆樹(shù)中存儲(chǔ)著所有添加到epoll中的需要監(jiān)控的事件*/struct rb_root rbr;/*雙鏈表中則存放著將要通過(guò)epoll_wait返回給用戶(hù)的滿(mǎn)足條件的事件*/struct list_head rdlist;....};

    每一個(gè)epoll對(duì)象都有一個(gè)獨(dú)立的eventpoll結(jié)構(gòu)體,用于存放通過(guò)epoll_ctl方法向epoll對(duì)象中添加進(jìn)來(lái)的事件。這些事件都會(huì)掛載在紅黑樹(shù)中,如此,重復(fù)添加的事件就可以通過(guò)紅黑樹(shù)而高效的識(shí)別出來(lái)(紅黑樹(shù)的插入時(shí)間效率是lgn,其中n為樹(shù)的高度)。

    而所有添加到epoll中的事件都會(huì)與設(shè)備(網(wǎng)卡)驅(qū)動(dòng)程序建立回調(diào)關(guān)系,也就是說(shuō),當(dāng)相應(yīng)的事件發(fā)生時(shí)會(huì)調(diào)用這個(gè)回調(diào)方法。這個(gè)回調(diào)方法在內(nèi)核中叫ep_poll_callback,它會(huì)將發(fā)生的事件添加到rdlist雙鏈表中。

    struct epitem{struct rb_node rbn;//紅黑樹(shù)節(jié)點(diǎn)struct list_head rdllink;//雙向鏈表節(jié)點(diǎn)struct epoll_filefd ffd; //事件句柄信息struct eventpoll *ep; //指向其所屬的eventpoll對(duì)象struct epoll_event event; //期待發(fā)生的事件類(lèi)型}

    當(dāng)調(diào)用epoll_wait檢查是否有事件發(fā)生時(shí),只需要檢查eventpoll對(duì)象中的rdlist雙鏈表中是否有epitem元素即可。如果rdlist不為空,則把發(fā)生的事件復(fù)制到用戶(hù)態(tài),同時(shí)將事件數(shù)量返回給用戶(hù)。

    select()

    select()簡(jiǎn)介

  • select()函數(shù)是阻塞的, 只有某些端口狀態(tài)轉(zhuǎn)換了或者達(dá)到timeout才會(huì)返回
  • 該函數(shù)可以允許進(jìn)程指示等待多個(gè)事件中任何一個(gè)的發(fā)生
  • select(), poll() 都是水平觸發(fā)
  • 為什么需要select()?

  • 多路復(fù)用io mutiplexing
  • 如果不采用多路復(fù)用,要么使用阻塞IO(會(huì)使線(xiàn)程長(zhǎng)時(shí)間處于阻塞狀態(tài),無(wú)法執(zhí)行任何計(jì)算或者響應(yīng)任何網(wǎng)絡(luò)請(qǐng)求),要么使用非阻塞IO:(要用while循環(huán)調(diào)用recv函數(shù),大幅占用CPU資源), 復(fù)用的優(yōu)勢(shì)在于可以同時(shí)處理多個(gè)連接
  • select()函數(shù)

    #include <sys/select.h> #include <sys/time.h>int select(int maxfdp1,fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);

    返回: 若有描述符就緒,則返回就緒描述符的數(shù)量,若超時(shí)則為0, 若出錯(cuò)則為1

    1. timeout-->timeval

    struct timeval {long tv_sec; // secondslog tv_usec; // microseconds }
    • 用于指定timeout的秒數(shù)和微秒數(shù)
    • 如果輸入為0,那么select函數(shù)會(huì)一直等下去一直到某個(gè)描述符準(zhǔn)備好
    • 如果輸入這個(gè)參數(shù),那么最長(zhǎng)等待時(shí)間就確定了
    • 如果輸入這個(gè)結(jié)構(gòu),但是其中的兩個(gè)值為0,那么就不等待-->輪詢(xún)機(jī)制

    延伸 gettimeofday()

    • 用gettimeofday() 可以獲得微秒(us)級(jí)別的時(shí)間。
    • 會(huì)把目前的時(shí)間tv所指的結(jié)構(gòu)返回,當(dāng)?shù)貢r(shí)區(qū)的信息則放到tz所指的結(jié)構(gòu)中。
    • 1970年1月1日到現(xiàn)在的時(shí)間
    • 調(diào)用兩次gettimeofday(), 前后做減法,從而達(dá)到計(jì)算時(shí)間的目的。
    #include <sys/time.h> int gettimeofday(struct timeval *tv,struct timezone *tz);

    2. readset, writeset, exceptset

    #include <sys/select.h>struct fd_set myset; //四個(gè)相關(guān)的宏函數(shù)void FD_ZERO(fd_set *fdset); // clean all bits at fdset void FD_SET(int fd, fd_set *fdset); // turn on the bit for fd in fdset void FD_CLR(int fd, fd_set *fdset); // turn on the bit for fd in fdset void FD_ISSET(int fd, fd_set *fdset); //is the bit for fd on in fdset? 如果set了,返回1
  • fd_set 每一位表示一個(gè)fd, set其中的某一位就表示要監(jiān)視某個(gè)fd.
  • 指針輸入, 輸入的時(shí)候把我們所關(guān)心的fd置為1. 返回時(shí),他將指示哪些描述符已經(jīng)就緒了。因此,每次重新調(diào)用select時(shí),我們都需要再次把所有我們關(guān)心的描述符置為1。
  • 3. maxfdp1

  • maxfdp1 = 最大描述符+1
  • 最大描述符系統(tǒng)內(nèi)是有定義的 FD_SETSIZE
  • 例子

    select\strcliselect01.c

    void str_cli(FILE *fp, int sockfd) {int maxfdp1;fd_set rset;char sendline[MAXLINE], recvline[MAXLINE];FD_ZERO(&rset);for ( ; ; ) {FD_SET(fileno(fp), &rset);FD_SET(sockfd, &rset);maxfdp1 = max(fileno(fp), sockfd) + 1;Select(maxfdp1, &rset, NULL, NULL, NULL);if (FD_ISSET(sockfd, &rset)) { /* socket is readable */if (Readline(sockfd, recvline, MAXLINE) == 0)err_quit("str_cli: server terminated prematurely");Fputs(recvline, stdout);}if (FD_ISSET(fileno(fp), &rset)) { /* input is readable */if (Fgets(sendline, MAXLINE, fp) == NULL)return; /* all done */Writen(sockfd, sendline, strlen(sendline));}} }

    select 缺點(diǎn)

  • 每次調(diào)用select,都需要把fd集合從用戶(hù)態(tài)拷貝到內(nèi)核態(tài),這個(gè)開(kāi)銷(xiāo)在fd很多時(shí)會(huì)很大
  • 同時(shí)每次調(diào)用select都需要在內(nèi)核遍歷傳遞進(jìn)來(lái)的所有fd,這個(gè)開(kāi)銷(xiāo)在fd很多時(shí)也很大
  • select支持的文件描述符數(shù)量太小了,默認(rèn)是1024
  • select() 文件描述符上限

    這個(gè)問(wèn)題的關(guān)鍵其實(shí)要先理解select關(guān)于文件描述符上限的原因

  • linux系統(tǒng)本身就有文件描述符上限,文件描述符的建立會(huì)連帶建立很多其它表項(xiàng),具體可以搜索文件描述符的詳解,也就是說(shuō)文件描述符一定會(huì)占用資源,那在有限的硬件條件下,文件描述符必定會(huì)有上限,我在ubuntu14.04的ECS里通過(guò)
  • cat /proc/sys/fs/file-max //結(jié)果99999
  • 進(jìn)程文件描述符上限user limit中nofile的soft limit,實(shí)際上這是單個(gè)用戶(hù)的文件描述符上限,通過(guò)
  • ulimit -n //結(jié)果65535

    soft limit可以修改,但是不能超過(guò)hard limit

    ulimit -Hn //結(jié)果65535
  • select函數(shù)本身限制,主要是頭文件中FD_SETSIZE的大小,一般來(lái)說(shuō)是1024,這就限定了select函數(shù)中的文件描述符上限,當(dāng)然可以做修改,但是需要重新編譯內(nèi)核,而且效果由于select的實(shí)現(xiàn)機(jī)制,會(huì)比較差
  • poll()

    #include <poll.h> #include <limits.h> /* for OPEN_MAX */ // 描述了poll的最大數(shù)量int poll(struct pollfd *fdarray, unsigned long nfds, int timeout);

    返回: 若有描述符就緒,則返回就緒描述符的數(shù)量,若超時(shí)則為0, 若出錯(cuò)則為1

    fdarray

    指向一個(gè)數(shù)組結(jié)構(gòu)第一個(gè)元素的指針,沒(méi)一個(gè)元素都是一個(gè)pollfd結(jié)構(gòu),使用這個(gè)結(jié)構(gòu),避免了select中使用一個(gè)參數(shù)既表示我們關(guān)心的值,又表示結(jié)果。

    struct pollfd {int fd; // 描述符short events; // 我們關(guān)心的狀態(tài)short revents; // 返回的結(jié)果 }

    nfds

    第一個(gè)參數(shù)中的數(shù)組元素的個(gè)數(shù)

    timeout

    timeout說(shuō)明
    INFTIM永遠(yuǎn)等待
    0立即返回,不阻塞進(jìn)程
    >?0等待指定的毫秒數(shù)

    poll() 文件描述符上限

    poll雖然不像select一樣受到select() 中FD_SETSIZE 的限制,但是仍然受到ulimit中設(shè)定的一個(gè)進(jìn)程所能打開(kāi)的最大文件描述符的限制

    ulimit -n //結(jié)果65535

    poll()/select()的區(qū)別

  • poll() 解決了select文件描述符最大只有1024的限制
  • select和poll都需要自己不斷輪詢(xún)所有fd集合,直到設(shè)備就緒,(首先把所有的fd掛到對(duì)應(yīng)的等待隊(duì)列上,然后睡眠,在設(shè)備收到一條消息或者填寫(xiě)完文件數(shù)據(jù)之后,會(huì)喚醒設(shè)備等待隊(duì)列上的進(jìn)程,進(jìn)程會(huì)再次掃描整個(gè)注冊(cè)文件描述符的集合,并返回就緒文件描述符的數(shù)目給用戶(hù))期間可能要睡眠和喚醒多次交替(存疑),雖然epoll也需要喚醒,但是喚醒之后只需要檢測(cè)就緒鏈表是否為空就行了。

  • 本篇文章由一文多發(fā)平臺(tái)ArtiPub自動(dòng)發(fā)布

    總結(jié)

    以上是生活随笔為你收集整理的linux网络编程--select/poll/epoll 详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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