select 、poll、epoll 的用法

0、引用?

http://www.cnblogs.com/Anker/p/3265058.html

http://janfan.github.io/chinese/2015/01/05/select-poll-impl-inside-the-kernel.html

http://blog.csdn.net/lizhiguo0532/article/details/6568957

http://blog.csdn.net/shuxiaogd/article/details/50366039

https://segmentfault.com/a/1190000003063859

1、select 函數(shù)

#define __FD_SETSIZE? ? 1024

typedef struct {

unsigned long fds_bits[__FD_SETSIZE / (8 * sizeof(long))];

} __kernel_fd_set;

typedef __kernel_fd_set? ? fd_set;

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

void FD_CLR(int fd, fd_set *set);

int? FD_ISSET(int fd, fd_set *set);

void FD_SET(int fd, fd_set *set);

void FD_ZERO(fd_set *set);

2、select執(zhí)行流程

1、把fd全部掃描一遍

2、如果發(fā)現(xiàn)有可用的fd,跳轉(zhuǎn)到5

3、如果沒(méi)有,當(dāng)前進(jìn)程去睡眠xx秒

4、xx秒后進(jìn)程自己醒了或者fd狀態(tài)的改變喚醒了進(jìn)程,跳轉(zhuǎn)到步驟1

5、結(jié)束循環(huán)體,返回

3、select 的缺點(diǎn)

(1)每次調(diào)用select,都需要把fd集合從用戶態(tài)拷貝到內(nèi)核態(tài),當(dāng)fd很多時(shí)這個(gè)開(kāi)銷(xiāo)會(huì)很大

(2)同時(shí)每次調(diào)用select都需要在內(nèi)核遍歷傳遞進(jìn)來(lái)的所有fd,當(dāng)fd很多時(shí)這個(gè)開(kāi)銷(xiāo)會(huì)很大

(3)select支持的文件描述符數(shù)量太小了,默認(rèn)是1024

4、poll 的實(shí)現(xiàn)

poll的實(shí)現(xiàn)和select非常相似,只是描述fd集合的方式不同,poll使用pollfd結(jié)構(gòu)而不是select的fd_set結(jié)構(gòu),其他的都差不多。

5、epoll的實(shí)現(xiàn)

int epoll_create(int size);

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

epoll是在2.6內(nèi)核中提出的,是之前的select和poll的增強(qiáng)版本。相對(duì)于select和poll來(lái)說(shuō),epoll更加靈活,沒(méi)有描述符限制。epoll使用一個(gè)文件描述符管理多個(gè)描述符,將用戶關(guān)系的文件描述符的事件存放到內(nèi)核的一個(gè)事件表中,這樣在用戶空間和內(nèi)核空間的copy只需一次。

5.1. int epoll_create(int size);

創(chuàng)建一個(gè)epoll的句柄,size用來(lái)告訴內(nèi)核這個(gè)監(jiān)聽(tīng)的數(shù)目一共有多大,這個(gè)參數(shù)不同于select()中的第一個(gè)參數(shù),給出最大監(jiān)聽(tīng)的fd+1的值,參數(shù)size并不是限制了epoll所能監(jiān)聽(tīng)的描述符最大個(gè)數(shù),只是對(duì)內(nèi)核初始分配內(nèi)部數(shù)據(jù)結(jié)構(gòu)的一個(gè)建議。當(dāng)創(chuàng)建好epoll句柄后,它就會(huì)占用一個(gè)fd值,在linux下如果查看/proc/進(jìn)程id/fd/,是能夠看到這個(gè)fd的,所以在使用完epoll后,必須調(diào)用close()關(guān)閉,否則可能導(dǎo)致fd被耗盡。

5.2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

函數(shù)是對(duì)指定描述符fd執(zhí)行op操作。

- epfd:是epoll_create()的返回值。

- op:表示op操作,用三個(gè)宏來(lái)表示:添加EPOLL_CTL_ADD,刪除EPOLL_CTL_DEL,修改EPOLL_CTL_MOD。分別添加、刪除和修改對(duì)fd的監(jiān)聽(tīng)事件。

- fd:是需要監(jiān)聽(tīng)的fd(文件描述符)

- epoll_event:是告訴內(nèi)核需要監(jiān)聽(tīng)什么事,struct epoll_event結(jié)構(gòu)如下:

struct epoll_event {

__uint32_t events;? /* Epoll events */

epoll_data_t data;? /* User data variable */

};

//events可以是以下幾個(gè)宏的集合:

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的話,需要再次把這個(gè)socket加入到EPOLL隊(duì)列里

5.3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

等待epfd上的io事件,最多返回maxevents個(gè)事件。

參數(shù)events用來(lái)從內(nèi)核得到事件的集合,maxevents告之內(nèi)核這個(gè)events有多大,這個(gè)maxevents的值不能大于創(chuàng)建epoll_create()時(shí)的size,參數(shù)timeout是超時(shí)時(shí)間(毫秒,0會(huì)立即返回,-1將不確定,也有說(shuō)法說(shuō)是永久阻塞)。該函數(shù)返回需要處理的事件數(shù)目,如返回0表示已超時(shí)。

5.4 epoll工作模式

epoll對(duì)文件描述符的操作有兩種模式:LT(level trigger)ET(edge trigger)。LT模式是默認(rèn)模式,LT模式與ET模式的區(qū)別如下:

LT模式:當(dāng)epoll_wait檢測(cè)到描述符事件發(fā)生并將此事件通知應(yīng)用程序,應(yīng)用程序可以不立即處理該事件。下次調(diào)用epoll_wait時(shí),會(huì)再次響應(yīng)應(yīng)用程序并通知此事件。

ET模式:當(dāng)epoll_wait檢測(cè)到描述符事件發(fā)生并將此事件通知應(yīng)用程序,應(yīng)用程序必須立即處理該事件。如果不處理,下次調(diào)用epoll_wait時(shí),不會(huì)再次響應(yīng)應(yīng)用程序并通知此事件。

1. LT模式

LT(level triggered)是缺省的工作方式,并且同時(shí)支持block和no-block socket.在這種做法中,內(nèi)核告訴你一個(gè)文件描述符是否就緒了,然后你可以對(duì)這個(gè)就緒的fd進(jìn)行IO操作。如果你不作任何操作,內(nèi)核還是會(huì)繼續(xù)通知你的。

2. ET模式

ET(edge-triggered)是高速工作方式,只支持no-block socket。在這種模式下,當(dāng)描述符從未就緒變?yōu)榫途w時(shí),內(nèi)核通過(guò)epoll告訴你。然后它會(huì)假設(shè)你知道文件描述符已經(jīng)就緒,并且不會(huì)再為那個(gè)文件描述符發(fā)送更多的就緒通知,直到你做了某些操作導(dǎo)致那個(gè)文件描述符不再為就緒狀態(tài)了(比如,你在發(fā)送,接收或者接收請(qǐng)求,或者發(fā)送接收的數(shù)據(jù)少于一定量時(shí)導(dǎo)致了一個(gè)EWOULDBLOCK 錯(cuò)誤)。但是請(qǐng)注意,如果一直不對(duì)這個(gè)fd作IO操作(從而導(dǎo)致它再次變成未就緒),內(nèi)核不會(huì)發(fā)送更多的通知(only once)

ET模式在很大程度上減少了epoll事件被重復(fù)觸發(fā)的次數(shù),因此效率要比LT模式高。epoll工作在ET模式的時(shí)候,必須使用非阻塞套接口,以避免由于一個(gè)文件句柄的阻塞讀/阻塞寫(xiě)操作把處理多個(gè)文件描述符的任務(wù)餓死。

6、select /epoll?

在 select/poll中,進(jìn)程只有在調(diào)用一定的方法后,內(nèi)核才對(duì)所有監(jiān)視的文件描述符進(jìn)行掃描,而epoll事先通過(guò)epoll_ctl()來(lái)注冊(cè)一 個(gè)文件描述符,一旦基于某個(gè)文件描述符就緒時(shí),內(nèi)核會(huì)采用類(lèi)似callback的回調(diào)機(jī)制,迅速激活這個(gè)文件描述符,當(dāng)進(jìn)程調(diào)用epoll_wait() 時(shí)便得到通知。(此處去掉了遍歷文件描述符,而是通過(guò)監(jiān)聽(tīng)回調(diào)的的機(jī)制。這正是epoll的魅力所在。)

epoll的優(yōu)點(diǎn)主要是一下幾個(gè)方面:

1. 監(jiān)視的描述符數(shù)量不受限制,它所支持的FD上限是最大可以打開(kāi)文件的數(shù)目,這個(gè)數(shù)字一般遠(yuǎn)大于2048,舉個(gè)例子,在1GB內(nèi)存的機(jī)器上大約是10萬(wàn)左 右,具體數(shù)目可以cat /proc/sys/fs/file-max察看,一般來(lái)說(shuō)這個(gè)數(shù)目和系統(tǒng)內(nèi)存關(guān)系很大。select的最大缺點(diǎn)就是進(jìn)程打開(kāi)的fd是有數(shù)量限制的。這對(duì) 于連接數(shù)量比較大的服務(wù)器來(lái)說(shuō)根本不能滿足。雖然也可以選擇多進(jìn)程的解決方案( Apache就是這樣實(shí)現(xiàn)的),不過(guò)雖然linux上面創(chuàng)建進(jìn)程的代價(jià)比較小,但仍舊是不可忽視的,加上進(jìn)程間數(shù)據(jù)同步遠(yuǎn)比不上線程間同步的高效,所以也不是一種完美的方案。IO的效率不會(huì)隨著監(jiān)視fd的數(shù)量的增長(zhǎng)而下降。epoll不同于select和poll輪詢的方式,而是通過(guò)每個(gè)fd定義的回調(diào)函數(shù)來(lái)實(shí)現(xiàn)的。只有就緒的fd才會(huì)執(zhí)行回調(diào)函數(shù)。

水平觸發(fā),只要可讀或可寫(xiě),事件會(huì)一直觸發(fā)

邊緣觸發(fā),只有從不可讀變?yōu)榭勺x、從不可寫(xiě)變成可寫(xiě),事件才會(huì)觸發(fā)

基于此,水平觸發(fā),socket不需要設(shè)置為non-block,因?yàn)橹灰|發(fā),就可以讀或?qū)憽?/p>

而對(duì)于水平觸發(fā),事件一旦觸發(fā),需要用戶一直讀,直到緩沖區(qū)數(shù)據(jù)全部讀完為止才可以,如果設(shè)置為block,在沒(méi)有數(shù)據(jù)可讀時(shí),就block了,需要用eagain錯(cuò)誤來(lái)告知用戶,數(shù)據(jù)讀完了,不用再讀了。

ET 模式是一種邊沿觸發(fā)模型,在它檢測(cè)到有 I/O 事件時(shí),通過(guò) epoll_wait 調(diào)用會(huì)得到有事件通知的文件描述符,每于每一個(gè)被通知的文件描述符,如可讀,則必須將該文件描述符一直讀到空,讓 errno 返回 EAGAIN 為止,否則下次的 epoll_wait 不會(huì)返

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,619評(píng)論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,155評(píng)論 3 425
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 177,635評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,539評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,255評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,646評(píng)論 1 326
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,655評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,838評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,399評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,146評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,338評(píng)論 1 372
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,893評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,565評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,983評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,257評(píng)論 1 292
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,059評(píng)論 3 397
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,296評(píng)論 2 376

推薦閱讀更多精彩內(nèi)容