色yeye在线视频观看_亚洲人亚洲精品成人网站_一级毛片免费播放_91精品一区二区中文字幕_一区二区三区日本视频_成人性生交大免费看

當前位置:首頁 > 嵌入式培訓 > 嵌入式學習 > 講師博文 > EPOLL的工作原理及流程

EPOLL的工作原理及流程 時間:2018-05-14      來源:未知

一.Epoll是什么?

epoll是個什么東東呢?按照man手冊的說法:是為處理大批量句柄而作了改進的poll。當然,這不是2.6內核才有的,它是在2.5.44內核中被引進的(epoll(4) is a new API introduced in Linux kernel 2.5.44),它幾乎具備了之前所說的一切優點,被公認為Linux2.6下性能最好的多路I/O就緒通知方法。

二.epoll與poll和select對比

[1]select 的缺點:

單個進程能夠監視的文件描述符的數量存在最大限制,通常是1024,當然可以更改數量,但由于select采用輪詢的方式掃描文件描述符,文件描述符數量越多,性能越差;(在linux內核頭文件中,有這樣的定義:#define __FD_SETSIZE 1024)

內核 / 用戶空間內存拷貝問題,select需要復制大量的句柄數據結構,產生巨大的開銷;

select返回的是含有整個句柄的數組,應用程序需要遍歷整個數組才能發現哪些句柄發生了事件;

select中應用程序如果沒有完成對一個已經就緒的文件描述符進行IO操作,那么之后每次select調用還是會將這些文件描述符通知進程。

相對于我們的select模型,我們的poll是使用鏈表保持文件描述符,因此沒有了監視文件數量的限制,但是2,3,4等缺點依舊存在。

拿select模型為例,假設我們的服務器需要支持100萬的并發連接,則在__FD_SETSIZE 為1024的情況下,則我們至少需要開辟1k個進程才能實現100萬的并發連接。除了進程間上下文切換的時間消耗外,從內核/用戶空間大量的無腦內存拷貝、數組輪詢等,是系統難以承受的。因此,基于select模型的服務器程序,要達到10萬級別的并發訪問,是一個很難完成的任務。

因此,該epoll上場了。

三.Epoll的工作原理

設想一下如下場景:有100萬個客戶端同時與一個服務器進程保持著TCP連接。而每一時刻,通常只有幾百上千個TCP連接是活躍的(事實上大部分場景都是這種情況)。如何實現這樣的高并發?

在select/poll時代,服務器進程每次都把這100萬個連接告訴操作系統(從用戶態復制句柄數據結構到內核態),讓操作系統內核去查詢這些套接字上是否有事件發生,輪詢完后,再將句柄數據復制到用戶態,讓服務器應用程序輪詢處理已發生的網絡事件,這一過程資源消耗較大,因此,select/poll一般只能處理幾千的并發連接。

epoll的設計和實現與select完全不同。epoll通過在Linux內核中申請一個簡易的文件系統(文件系統一般用什么數據結構實現?二叉樹樹)。然后epoll的調用分成了3個部分:

1)調用epoll_create()建立一個epoll對象(在epoll文件系統中為這個句柄對象分配資源)

2)調用epoll_ctl向epoll對象中添加這100萬個連接的套接字

3)調用epoll_wait收集發生的事件的連接

如此一來,要實現上面說是的場景,只需要在進程啟動時建立一個epoll對象,然后在需要的時候向這個epoll對象中添加或者刪除連接。同時,epoll_wait的效率也非常高,因為調用epoll_wait時,并沒有一股腦的向操作系統復制這100萬個連接的句柄數據,內核也不需要去遍歷全部的連接。

具體流程:

[1]當我們某個進程調用epoll_create()函數的時候,linux內核會默認創建一個eventpoll結構體,這個結構體中有兩個成員與epoll的使用方式相關。

每一個epoll對象都有一個獨立的eventpoll結構體,用于存放通過epoll_ctl方法向epoll對象中添加進來的事件。這些事件都會掛載在紅黑樹中,如此,重復添加的事件就可以通過紅黑樹而高效的識別出來.

而所有添加到epoll中的事件都會與設備(網卡)驅動程序建立回調關系,也就是說,當相應的事件發生時會調用這個回調方法。這個回調方法在內核中叫ep_poll_callback,它會將發生的事件epitem添加到rdlist雙鏈表中。

在epoll中,對于每一個事件,都會建立一個epitem結構體,如下所示:

當調用epoll_wait檢查是否有事件發生時,只需要檢查eventpoll對象中的rdlist雙鏈表中是否有epitem元素即可。如果rdlist不為空,則把發生的事件復制到用戶態,同時將事件數量返回給用戶。

總結:

(1)我們我們調用epoll_wait()函數的時候,系統創建一個epoll對象,每個對象都有一個

叫做eventpoll類型的結構體與之對應,該結構體中主要有兩個主要的成員,一個是

rbn,代表將要通過epoll_ctl向epll對象中添加的事件。這些事情都是掛載在紅黑樹中。

一個是rdlist,里面存放的是將要發生的事件

(2)當我們使用epoll_ctrl()函數的時候,就是向epoll對象中添加,刪除,修改感興趣的事件

(3) epoll_wait()系統。通過此調用收集在epoll監控中已經發生的事件。當監控的事件狀態發生改變的時候,我們會調用會調用函數把epitem加入到rdlist中去。

一. Epoll的API函數接口

3.1 事件的創建---epoll_create();

int epoll_create(int size);

int epoll_create1(int flags);

功能:poll_create()創建一個epoll的事例,通知內核需要監聽size個fd。size指的并不是最大的后備存儲設備,而是衡量內核內部結構大小的一個提示。當創建成功后,會占用一個fd,所以記得在使用完之后調用close(),否則fd可能會被耗盡。

Note:自從Linux2.6.8版本以后,size值其實是沒什么用的,不過要大于0,因為內核可以動態的分配大小,所以不需要size這個提示了。

其次:epoll_create1()函數,其實它和epoll_create差不多,不同的是epoll_create1函參數flag:

· 當flag是0時,表示和epoll_create函數完全一樣,不需要size的提示了;

· 當flag = EPOLL_CLOEXEC,創建的epfd會設置FD_CLOEXEC;

· 當flag = EPOLL_NONBLOCK,創建的epfd會設置為非阻塞。

一般用法都是使用EPOLL_CLOEXEC。

Note:關于FD_CLOEXEC,它是fd的一個標識說明,用來設置文件close-on-exec狀態的。當close-on-exec狀態為0時,調用exec時,fd不會被關閉;狀態非零時則會被關閉,這樣做可以防止fd泄露給執行exec后的進程。

返回值:成功返回一個非負的文件描述符。

例如:

int epfd = epoll_create(20); //注:20為隨機寫的一個值,大于0即可。

int epfd = epoll_create1(0);

3.1 事件的注冊---epoll_ctl();

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

功能:epoll的事件注冊函數,epoll的事件注冊函數,它不同于select()是在監聽事件時告訴內核要監聽什么類型的事件,而是在這里先注冊要監聽的事件類型。

參數:

@epfd epoll_create()函數的返回值

@op 表示參數的動作,常用以下宏:

EPOLL_CTL_ADD:注冊新的fd到epfd中;

EPOLL_CTL_MOD:修改已經注冊的fd的監聽事件;

EPOLL_CTL_DEL:從epfd中刪除一個fd;

@fd 表示我們需要監聽的文件描述符

@event 表示告訴內核,我們需要監聽什么事件。

結構體如下:

typedef union epoll_data

{

void *ptr;

int fd; //保存我們使用的sockfd

uint32_t u32;

uint64_t u64;

} epoll_data_t;

struct epoll_event

{

uint32_t events; /* Epoll events */

epoll_data_t data; /* User data variable */

};

events參數是一個枚舉的集合,可以用” | “來增加事件類型,枚舉如下:

· EPOLLIN :表示對應的文件描述符可以讀(包括對端SOCKET正常關閉);

· EPOLLOUT:表示對應的文件描述符可以寫;

· EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這里應該表示有帶外數據到來);

· EPOLLERR:表示對應的文件描述符發生錯誤;

· EPOLLHUP:表示對應的文件描述符被掛斷;

· EPOLLET: 將EPOLL設為邊緣觸發(Edge Triggered)模式,這是相對于水平觸發(Level Triggered)來說的;

· EPOLLONESHOT:只監聽一次事件,當監聽完這次事件之后,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL隊列里

返回值:成功返回0,失敗返回-1.

3.2等待事件---epoll_wait();

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

功能:收集在epoll監控的事件中已經發送的事件。

參數:

@epfd epoll_create()函數的返回值

@events 已經分配好的epoll_event結構體數組,epoll會把將發生的事情存放到events中。

@maxevents 告訴內核events有多大。必須大于0

@timeout 超時時間 -1 表示epoll將無限制的等待下去

0 立即返回

>0 指定超時時間

返回值: 成功返回已經就緒的文件描述符個數。若是設置了超時時間,在超時時間內返回0.

失敗返回-1.

五.Epoll的工作模式。

LT(level triggered)是缺省的工作方式,并且同時支

持block和no-block socket.在這種做法中,。當epoll_wait檢測到描述符事件發生并將此事件通知應用程序,應用程序可以不立即處理該事件。下次調用epoll_wait時,會再次響應應用程序并通知此事件。

ET (edge-triggered)是高速工作方式,常工作在no-block socket。在這種模式下,當epoll_wait檢測到描述符事件發生并將此事件通知應用程序,應用程序必須立即處理該事件。如果不處理,下次調用epoll_wait時,不會再次響應應用程序并通知此事件。

EPOLLIN事件:

EPOLLIN事件則只有當對端有數據寫入時才會觸發,所以觸發一次后需要不斷讀取所有數據直到讀完EAGAIN為止。否則剩下的數據只有在下次對端有寫入時才能一起取出來了。設想這樣一個場景:接收端接收完整的數據后會向對端發送應答報文,

,對端才會繼續向接收端發送數據,從而觸發下一次的EPOLLIN,而這時沒有讀完socket緩沖區中的所有數據,導致接收端無法向對端發送應答報文,而對端沒有收到應答報文,也就不會再發送數據觸發下一次的EPOLLIN,而沒有下一次的EPOLLIN事件,接收端也就永遠不知道此socket緩沖區中還有未讀出的數據。一個完美的死循環)

示例代碼:

實現多個客戶端和服務端的回射代碼。

Server.c






Client.c





運行結果:

上一篇:想學單片機和嵌入式該怎么學 干貨力薦

下一篇:Kobject 與 sysfs 文件系統框架的分析

熱點文章推薦
華清學員就業榜單
高薪學員經驗分享
熱點新聞推薦
前臺專線:010-82525158 企業培訓洽談專線:010-82525379 院校合作洽談專線:010-82525379 Copyright © 2004-2022 北京華清遠見科技集團有限公司 版權所有 ,京ICP備16055225號-5京公海網安備11010802025203號

回到頂部

主站蜘蛛池模板: 免费人成再在线观看视频 | 麻豆传媒免费入口 | 无码人妻精品中文字幕 | 一个人在线观看www高清视频 | 精品日产乱码久久久久久仙踪林 | 无码中文字幕av免费放 | 无码免费无线观看在线视频 | 太大太粗太爽免费视频 | 亚洲精品无码MV在线观看 | 亚洲αv在线精品糸列 | 亚洲av乱码一区二区三区 | 天天插天天舔 | 色婷婷亚洲六月婷婷中文字幕 | 国外精品视频在线观看免费 | 亚洲妇女自偷自偷图片 | 亚洲欧美日韩在线不卡 | 中文无码乱人伦中文视频播放 | 麻豆做爰免费观看 | 欧美精品手机在线 | 未满岁18禁止在线WWW | 国产成人综合久久精品 | 亚洲国产精品日本无码十八禁 | 在线免费观看黄色大片 | 超碰人人模人人爽人人喊手机版 | 国产女人高潮叫床视频捆绑 | 亚洲一区二区三区AV无码 | 国产午夜精品久久久久久 | 麻豆免费高清在线观看 | 亚洲综合无码一区二区加勒此 | 国产内射999视频一区 | 午夜亚洲WWW湿好爽 国产成人啪精品视频免费视频 | 国产在线一卡 | 5060网永久免费a级毛片 | 久久av无码αv高潮αv喷吹 | 亚洲精品中文字幕无码A片老 | 国产成人A在线观看网站站 亚洲日韩中文第一精品 | 男女一边摸一边做爽爽的免费阅读 | 日本高清视频色WWW色 | 强奷漂亮少妇高潮在线观看 | 免费国产黄网站在线观看 | 国产网址在线观看 |