您好,登錄后才能下訂單哦!
epoll就是為了 處理大批量句柄而改進的poll,相比與select,poll最大的好處在于它不會隨著堅挺fd的數目增長而效率降低。因為在內核中的select是采用輪詢來處理的,輪詢fd的數目越多,自然耗時越多,并且slelct的監聽數目有限(雖然可以通過頭文件來改變,但并不治本)
一.epoll的相關系統調用
epoll只有三個簡單地接口 分別為epoll_creat,epoll_ctl,epoll_wait
(1)int epoll_creat(int size)
創建一個epoll句柄,當創建好一個epoll句柄后,它就會占一個 fd值,所以在使用完以后要調用close()函數關閉,否則fd可能被耗盡
(2)int epoll_ctl(int epfd,int op,int fd,struct epoll_event* event)
epoll的事件注冊函數,它不同于 select函數在監聽事件的時候告訴內核要監聽什么類型的事件,而是 在 這里先注冊要監聽的事件類型
第一個參數是epoll_creat的返回值
第二個參數表示動作,用三個宏來表示
EPOLL_CTL_ADD:注冊新的fd到epfd中
EPOLL_CTL_MOD;修改已經注冊到的fd的監聽事件
EPOLL_CTL_DEL:從epfd中刪除一個fd
第三個參數 是 要監聽 的fd
第四個參數 告訴內核 需要監聽什么 事件
event可以是以下幾個 宏的集合
EPOLLIN:表示 對應的文件描述符可以讀(包括對socket正常關閉)
EPOLLOUT:表示 對應的文件描述符可以寫
EPOLLPRI:表示對應的文件描述符有緊急的數據可讀
EPOLLERR:對應的文件描述符發生錯誤
EPOLLET:將EPOLL設置為 邊沿除法模式 ,這是相對于水平觸發而言
EPOLLONESET:只監聽一次事件,如果之后還需要監聽的話,需要再次把這個socket鍵入到EPOLL隊列里
(3)int epoll_wait(int epfd,struct epoll_event* events,int maxevents,int timeout)
收集epoll監控的事件中已經發生的事件參數event是分配好的epoll_event結構體數組。epoll把發生的事件賦值到events數組中 (events不可以是空指針,內核只負責把數據復制到數組中,但不會幫用戶開辟內存),maxevents告訴這個內核有多大這個maxevents的值不能大于創建的epoll_ctreat()時的size,闡述timeout是超時事件(毫秒 ,0立即返回,-1將不確定,也就是永久阻塞)如果函數調用成功,返回對應已準備好的文件描述符數目,如果返回0表示超時
二. epoll工作原理
epoll只告訴那些就緒的文件描述符,而且當你調用epoll_wait()獲得就緒文件描述符的時候,返回的不是實際的文件描述符,而是一個代表就緒描述符數量值,你只是需要去epoll指定的一個數組 中一次獲得相應數量的文件描述符即可。
另一個本質的改進在于epoll采用基于 事件的就緒通知方式,在select/poll中進程只有在調用一定的方法之后,內核才對所有監視的文件描述符進行掃描,而epoll先通過采用epoll_ctl()來注冊一個文件描述符,當進程調用epoll_wait()時便得到通知。
三. epoll的工作方式-水平觸發(LT)-邊沿觸發(ET)
LT(level triggered)是epoll缺省的工作方式,并且同時支持block和no-block socket.在這種做法中,內核告訴你一個文件描述符是否就緒了,然后你可以對這個就緒的fd進行IO操作。如果你不作任何操作,內核還是會繼續通知你 的,所以,這種模式編程出錯誤可能性要小一點。傳統的select/poll都是這種模型的代表.
ET (edge-triggered)是高速工作方式,只支持no-block socket,它效率要比LT更高。ET與LT的區別在于,當一個新的事件到來時,ET模式下當然可以從epoll_wait調用中獲取到這個事件,可是如果這次沒有把這個事件對應的套接字緩沖區處理完,在這個套接字中沒有新的事件再次到來時,在ET模式下是無法再次從epoll_wait調用中獲取這個事件的。而LT模式正好相反,只要一個事件對應的套接字緩沖區還有數據,就總能從epoll_wait中獲取這個事件。
因此,LT模式下開發基于epoll的應用要簡單些,不太容易出錯。而在ET模式下事件發生時,如果沒有徹底地將緩沖區數據處理完,則會導致緩沖區中的用戶請求得不到響應
四.epoll的優點
(1)支持一個進程打開大數目的socket描述符(FD)
select所能夠打開的fd是有限的一般為1024,對于那些支持上萬條鏈接數目的服務器來說 太少了,epoll就沒有這個限制 ,它所支持的FD上限是最大可以打開文件數目這個樹種子一般大于2048;
(2)IO效率不隨FD的數目 增加而線性下降
傳統的select/poll致命弱點是當擁有一個很大的集合的時候,每次都用都會輪詢掃描 集合 ,導致效率下降,但是epoll只對活躍 的socket進行操作--因為在內核中epoll根據每個fd上面的callback函數實現的,只有活躍的函數 才會 調用 callback函數
五.linux下epoll如何處理百萬句柄
(1)首先調用epoll_creat建立一個epoll對象,參數 size是內核保證能夠正確處理的最大句柄數
(2)epoll_ctl操作上面建立好的epoll,例如讓剛建立的socket加入到epoll中讓其監控,或者把epoll正在監控的某個socke句柄移除epoll
(3)epoll_wait在給定的timeout時間內當監控的所有句柄發審核變化時就返回用戶態進程(毫秒 ,0立即返回,-1將不確定,也就是永久阻塞)如果函數調用成功,返回對應已準備好的文件描述符數目,如果返回0表示超時
從上面調用方式可以看出epoll比select/poll的優越之處:因為 后者每次調用時都會給你返回所要監控所有socket給select/poll系統 調用 ,這意味著需要將用戶態的socket列表 拷貝到內核態,如果數以萬計的句柄會導致每次都要copy幾十幾百KB的內存到內核態,非常低效,但epoll_wait不用傳遞socket句柄給內核,因為內核已經在 epoll_ctl中拿到了要監控的句柄列表
下面是代碼部分
1.創建監聽套接字,設置端口服用127.0.0.1 指定簇為 IPv4,指定端口號并 轉化為 網絡字節序列,指定ip地址并轉化為 網絡 字節序列
2.調用epoll_creat得到一個epoll模型,判斷若創建成功,則調用epoll_ctl函數注冊要監聽事件的類型 ,本代碼中設置的監聽事件類型為EPOLLIN:表示 對應的文件描述符可以讀
epoll的事件注冊函數,它不同于 select函數在監聽事件的時候告訴內核要監聽什么類型的事件,而是 在 這里先注冊要監聽的事件類型
第一個參數是epoll_creat的返回值
第二個參數表示動作,用三個宏來表示
EPOLL_CTL_ADD:注冊新的fd到epfd中
EPOLL_CTL_MOD;修改已經注冊到的fd的監聽事件
EPOLL_CTL_DEL:從epfd中刪除一個fd
第三個參數 是 要監聽 的fd
第四個參數 告訴內核 需要監聽什么 事件
event可以是以下幾個 宏的集合
EPOLLIN:表示 對應的文件描述符可以讀(包括對socket正常關閉)
EPOLLOUT:表示 對應的文件描述符可以寫
EPOLLPRI:表示對應的文件描述符有緊急的數據可讀
EPOLLERR:對應的文件描述符發生錯誤
EPOLLET:將EPOLL設置為 邊沿除法模式 ,這是相對于水平觸發而言
EPOLLONESET:只監聽一次事件,如果之后還需要監聽的話,需要再次把這個socket鍵入到EPOLL隊列里
3.調用epoll_wait函數收集epoll監控的事件中已經發生的事件,參數event是分配好的epoll_event結構體數組。epoll把發生的事件賦值到events數組中 (events不可以是空指針,內核只負責把數據復制到數組中,但不會幫用戶開辟內存),maxevents告訴這個內核有多大這個maxevents的值不能大于創建的epoll_ctreat()時的size,
闡述timeout是超時事件(毫秒 ,0立即返回,-1將不確定,也就是永久阻塞)如果函數調用成功,返回對應已準備好的文件描述符數目,如果返回0表示超時
判斷它是否為 監聽套接字,如果是并且就緒 則對它進行接收,并且以邊沿出讓的方式讀入 ,若是其他套接字 ,則對他進行同樣的 接收
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。