Java NIO(二)深入理解 epoll

參考視頻:https://www.bilibili.com/video/BV12i4y1G7UK?from=search&seid=12243469803670169476

epoll模型是在單個(gè)線程中偵聽多個(gè)套接字fd行為的一種IO多路復(fù)用模型。主要有epoll_create,epoll_ctl,epoll_wait三個(gè)接口微峰。

一沛厨、epoll的使用

1. 創(chuàng)建epoll句柄

int epfd = epoll_create(intsize);

創(chuàng)建一個(gè)epoll的句柄,size用來告訴內(nèi)核這個(gè)監(jiān)聽的數(shù)目一共有多大杜耙。size就是你在這個(gè)epoll fd上能關(guān)注的最大socket fd數(shù)成榜。

2.將被監(jiān)聽的描述符添加到epoll句柄或從epool句柄中刪除或者對監(jiān)聽事件進(jìn)行修改桐智。

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

參數(shù):

epfd:由 epoll_create 生成的epoll專用的文件描述符;

op:要進(jìn)行的操作例如注冊事件辩尊,可能的取值EPOLL_CTL_ADD 注冊涛浙、EPOLL_CTL_MOD 修 改、EPOLL_CTL_DEL 刪除

fd:關(guān)聯(lián)的文件描述符;

event:指向epoll_event的指針轿亮;

如果調(diào)用成功返回0,不成功返回-1

第一個(gè)參數(shù)是epoll_create()的返回值疮薇,

第二個(gè)參數(shù)表示動(dòng)作,用三個(gè)宏來表示:

EPOLL_CTL_ADD:? ? ? 注冊新的fd到epfd中我注;

EPOLL_CTL_MOD:? ? ? 修改已經(jīng)注冊的fd的監(jiān)聽事件按咒;

EPOLL_CTL_DEL:? ? ? ? 從epfd中刪除一個(gè)fd;

第三個(gè)參數(shù)是需要監(jiān)聽的fd但骨,

第四個(gè)參數(shù)是告訴內(nèi)核需要監(jiān)聽什么事件励七,structepoll_event結(jié)構(gòu)如下:

typedefunionepoll_data{void*ptr;//指向要附加的數(shù)據(jù)結(jié)構(gòu)intfd;//一般設(shè)為監(jiān)視的fd__uint32_t u32;__uint64_t u64;}epoll_data_t;structepoll_event{/* Epoll events

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

? ? ? ? EPOLLIN:? ? ? ? ? ? 觸發(fā)該事件,表示對應(yīng)的文件描述符上有可讀數(shù)據(jù)奔缠。(包括對端SOCKET正常關(guān)閉)掠抬;

? ? ? ? EPOLLOUT:? ? ? ? 觸發(fā)該事件,表示對應(yīng)的文件描述符上可以寫數(shù)據(jù)校哎;

? ? ? ? EPOLLPRI:? ? ? ? ? 表示對應(yīng)的文件描述符有緊急的數(shù)據(jù)可讀(這里應(yīng)該表示有帶外數(shù)據(jù)到來)两波;

? ? ? ? EPOLLERR:? ? ? ? 表示對應(yīng)的文件描述符發(fā)生錯(cuò)誤;

? ? ? ? EPOLLHUP:? ? ? ? 表示對應(yīng)的文件描述符被掛斷贬蛙;

? ? ? ? EPOLLET:? ? ? ? ? 將EPOLL設(shè)為邊緣觸發(fā)(Edge Triggered)模式雨女,這是相對于水平觸發(fā)(Level Triggered)來說的。

? ? ? ? EPOLLONESHOT:? 只監(jiān)聽一次事件阳准,當(dāng)監(jiān)聽完這次事件之后,如果還需要繼續(xù)監(jiān)聽這個(gè)socket的話馏臭,需要再次把這個(gè)socket加入到EPOLL隊(duì)列里野蝇。

*/__uint32_t events;epoll_data_t data;/* User data variable */};

如要監(jiān)聽服務(wù)端套接字的連接,listenfd對對應(yīng)的socket套接字括儒,之前已經(jīng)bind和listen好绕沈。將它加入到epfd指定的epoll對象中

structepoll_eventev;//設(shè)置與要處理的事件相關(guān)的文件描述符ev.data.fd=listenfd;//設(shè)置要處理的事件類型ev.events=EPOLLIN|EPOLLET;//注冊epoll事件epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);

3.等待事件觸發(fā),當(dāng)超過timeout還沒有事件觸發(fā)時(shí)帮寻,就超時(shí)乍狐。

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

函數(shù)聲明:int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)

該函數(shù)用于輪詢I/O事件的發(fā)生;參數(shù):

epfd:由epoll_create 生成的epoll專用的文件描述符固逗;

epoll_event:用于回傳代處理事件的數(shù)組浅蚪,已經(jīng)分配好內(nèi)存;

maxevents:每次能處理的最大事件數(shù)烫罩;

timeout:等待I/O事件發(fā)生的超時(shí)值(單位我也不太清楚)惜傲;-1相當(dāng)于阻塞,0相當(dāng)于非阻塞贝攒。一般用-1即可

返回發(fā)生事件數(shù)盗誊。

二、epoll的原理

本節(jié)會(huì)以示例和圖表來講解epoll的原理和流程。

1.創(chuàng)建epoll對象

如下圖所示哈踱,當(dāng)某個(gè)進(jìn)程調(diào)用epoll_create方法時(shí)荒适,內(nèi)核會(huì)創(chuàng)建一個(gè)eventpoll對象(也就是程序中epfd所代表的對象)。eventpoll對象也是文件系統(tǒng)中的一員开镣,和socket一樣吻贿,它也會(huì)有等待隊(duì)列。

內(nèi)核創(chuàng)建eventpoll對象

創(chuàng)建一個(gè)代表該epoll的eventpoll對象是必須的哑子,因?yàn)閮?nèi)核要維護(hù)“就緒列表”等數(shù)據(jù)舅列,“就緒列表”可以作為eventpoll的成員。

2.維護(hù)監(jiān)視列表

創(chuàng)建epoll對象后卧蜓,可以用epoll_ctl添加或刪除所要監(jiān)聽的socket帐要。以添加socket為例,如下圖弥奸,如果通過epoll_ctl添加sock1榨惠、sock2和sock3的監(jiān)視,內(nèi)核會(huì)將eventpoll添加到這三個(gè)socket的等待隊(duì)列中盛霎。

添加所要監(jiān)聽的socket

當(dāng)socket收到數(shù)據(jù)后赠橙,中斷程序會(huì)操作eventpoll對象,而不是直接操作進(jìn)程愤炸。

3.接收數(shù)據(jù)

當(dāng)socket收到數(shù)據(jù)后期揪,中斷程序會(huì)給eventpoll的“就緒列表”添加socket引用。如下圖展示的是sock2和sock3收到數(shù)據(jù)后规个,中斷程序讓rdlist引用這兩個(gè)socket凤薛。

給就緒列表添加引用

eventpoll對象相當(dāng)于是socket和進(jìn)程之間的中介,socket的數(shù)據(jù)接收并不直接影響進(jìn)程诞仓,而是通過改變eventpoll的就緒列表來改變進(jìn)程狀態(tài)缤苫。

當(dāng)程序執(zhí)行到epoll_wait時(shí),如果rdlist已經(jīng)引用了socket墅拭,那么epoll_wait直接返回活玲,如果rdlist為空,阻塞進(jìn)程谍婉。

4.阻塞和喚醒進(jìn)程

假設(shè)計(jì)算機(jī)中正在運(yùn)行進(jìn)程A和進(jìn)程B舒憾,在某時(shí)刻進(jìn)程A運(yùn)行到了epoll_wait語句。如下圖所示屡萤,內(nèi)核會(huì)將進(jìn)程A放入eventpoll的等待隊(duì)列中珍剑,阻塞進(jìn)程。

epoll_wait阻塞進(jìn)程

當(dāng)socket接收到數(shù)據(jù)死陆,中斷程序一方面修改rdlist招拙,另一方面喚醒eventpoll等待隊(duì)列中的進(jìn)程唧瘾,進(jìn)程A再次進(jìn)入運(yùn)行狀態(tài)(如下圖)。也因?yàn)閞dlist的存在别凤,進(jìn)程A可以知道哪些socket發(fā)生了變化饰序。

epoll喚醒進(jìn)程

三、epoll的實(shí)現(xiàn)細(xì)節(jié)

讀完這篇文章规哪,還有三個(gè)問題需要細(xì)究一下求豫。

eventpoll的數(shù)據(jù)結(jié)構(gòu)是什么樣子?

就緒隊(duì)列應(yīng)該應(yīng)使用什么數(shù)據(jù)結(jié)構(gòu)诉稍?

eventpoll應(yīng)使用什么數(shù)據(jù)結(jié)構(gòu)來管理通過epoll_ctl添加或刪除的socket蝠嘉?

如下圖所示,eventpoll包含了lock杯巨、mtx蚤告、wq(等待隊(duì)列)、rdlist等成員服爷。rdlist和rbr是我們所關(guān)心的杜恰。

epoll原理示意圖

1. 就緒列表的數(shù)據(jù)結(jié)構(gòu)

就緒列表引用著就緒的socket,所以它應(yīng)能夠快速的插入數(shù)據(jù)仍源。

程序可能隨時(shí)調(diào)用epoll_ctl添加監(jiān)視socket心褐,也可能隨時(shí)刪除。當(dāng)刪除時(shí)笼踩,若該socket已經(jīng)存放在就緒列表中逗爹,它也應(yīng)該被移除。

所以就緒列表應(yīng)是一種能夠快速插入和刪除的數(shù)據(jù)結(jié)構(gòu)戳表。雙向鏈表就是這樣一種數(shù)據(jù)結(jié)構(gòu)桶至,epoll使用雙向鏈表來實(shí)現(xiàn)就緒隊(duì)列(對應(yīng)上圖的rdllist)。

2.索引結(jié)構(gòu)

既然epoll將“維護(hù)監(jiān)視隊(duì)列”和“進(jìn)程阻塞”分離匾旭,也意味著需要有個(gè)數(shù)據(jù)結(jié)構(gòu)來保存監(jiān)視的socket。至少要方便的添加和移除圃郊,還要便于搜索价涝,以避免重復(fù)添加。紅黑樹是一種自平衡二叉查找樹持舆,搜索色瘩、插入和刪除時(shí)間復(fù)雜度都是O(log(N)),效率較好逸寓。epoll使用了紅黑樹作為索引結(jié)構(gòu)(對應(yīng)上圖的rbr)居兆,存儲(chǔ)所監(jiān)視的socket fd。

作者:hjx_zju

鏈接:http://www.reibang.com/p/4c50e740ddd5

來源:簡書

著作權(quán)歸作者所有竹伸。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)泥栖,非商業(yè)轉(zhuǎn)載請注明出處簇宽。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市吧享,隨后出現(xiàn)的幾起案子魏割,更是在濱河造成了極大的恐慌,老刑警劉巖钢颂,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钞它,死亡現(xiàn)場離奇詭異,居然都是意外死亡殊鞭,警方通過查閱死者的電腦和手機(jī)遭垛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來操灿,“玉大人锯仪,你說我怎么就攤上這事∩撸” “怎么了卵酪?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長谤碳。 經(jīng)常有香客問我溃卡,道長,這世上最難降的妖魔是什么蜒简? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任瘸羡,我火速辦了婚禮,結(jié)果婚禮上搓茬,老公的妹妹穿的比我還像新娘犹赖。我一直安慰自己,他們只是感情好卷仑,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布峻村。 她就那樣靜靜地躺著,像睡著了一般锡凝。 火紅的嫁衣襯著肌膚如雪粘昨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天窜锯,我揣著相機(jī)與錄音张肾,去河邊找鬼。 笑死锚扎,一個(gè)胖子當(dāng)著我的面吹牛吞瞪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播驾孔,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼芍秆,長吁一口氣:“原來是場噩夢啊……” “哼惯疙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起浪听,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤螟碎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后迹栓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掉分,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年克伊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了酥郭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡愿吹,死狀恐怖不从,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情犁跪,我是刑警寧澤椿息,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站坷衍,受9級特大地震影響寝优,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜枫耳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一乏矾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧迁杨,春花似錦钻心、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至狐史,卻和暖如春亿胸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背预皇。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留婉刀,地道東北人吟温。 一個(gè)月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像突颊,于是被迫代替她去往敵國和親鲁豪。 傳聞我的和親對象是個(gè)殘疾皇子潘悼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345