歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> epol學習筆記

epol學習筆記

日期:2017/2/28 13:53:21   编辑:Linux教程

epoll的相關系統調用

epoll_create()

epoll_ctl()

epoll_wait()

int epoll_create(int size);

創建一個epoll的句柄。

  1. 自從linux2.6.8之後,size參數是被忽略的。
  2. 創建epoll句柄後,它就是會占用一個fd值,在使用完epoll後,必須調用close()關閉。

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

epoll的事件注冊函數。

  1. 第一個參數是epoll_create()的返回值。

  2. 第二個參數表示動作,用三個宏來表示:

    EPOLL_CTL_ADD:注冊新的fd到epfd中;

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

    EPOLL_CTL_DEL:從epfd中刪除一個fd。

  3. 第三個參數是需要監聽的fd。

  4. 第四個參數是告訴內核需要監聽什麼事。

struct 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 */

};

events可以是以下幾個宏的集合:

  1. EPOLLIN:表示對應的文件描述符可以讀(包括對端SOCKET正常關閉);
  2. EPOLLOUT:表示對應的文件描述符可以寫;
  3. EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這裡應該表示有帶外數據到來);
  4. EPOLLERR:表示對應的文件描述符發生錯誤;
  5. EPOLLHUP:表示對應的文件描述符被掛斷;
  6. EPOLLET:將EPOLL設為邊緣觸發(Edge Triggered)模式,這是相對於水平觸發(Level Triggered)來說的。
  7. EPOLLONESHOT:只監聽一次事件,當監聽完這次事件之後,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL隊列裡。

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

收集在epoll監控的事件中已經發生的事件。

  1. 參數events是分配好的epoll_event結構體數組,epoll將會把發生的事件賦值到events數組中(events不可以是空指針,內核只負責把數據復制到這個events數組中,不會去幫助我們在用戶態中分配內存)。
  2. maxevents告之內核這個events有多大,這個maxevents的值不能大於創建epoll_create()時的size。(自從linux2.6.8之後,size參數是被忽略的。)maxevents值使用cat /proc/sys/fs/file-max命令查詢,與內存的大小有關。
  3. 最後一個timeout是epoll_wait的超時,為0的時候表示馬上返回,為-1的時候表示一直等下去,直到有事件發生,為任意正整數的時候表示等這麼長的時間,如果一直沒有事件,則返回。一般如果網絡主循環是單獨的線程的話,可以用-1來等,這樣可以保證一些效率,如果是和主邏輯在同一個線程的話,則可以用0來保證主循環的效率。
  4. 如果函數調用成功,返回對應I/O上已准備好的文件描述符數目,如返回0表示已超時。

Edge Triggered 工作模式

  1. epoll工作在ET模式的時候,必須使用非阻塞套接口,以避免由於一個文件句柄的阻塞讀/阻塞寫操作把處理多個文件描述符的任務餓死。
  2. 最好以下面的方式調用ET模式的epoll接口,在後面會介紹避免可能的缺陷。

@ 基於非阻塞文件句柄

@ 只有當read()或者write()返回EAGAIN時才需要掛起,等待。

但這並不是說每次read()時都需要循環讀,直到讀到產生一個EAGAIN才認為此次事件處理完成,當read()返回的讀到的數據長度小於請求的數據長度時,就可以確定此時緩沖中已沒有數據了,也就可以認為此事讀事件已處理完成。

Copyright © Linux教程網 All Rights Reserved