2021-05-12 14:32:11
epol學習筆記
epoll的相關系統呼叫
epoll_create()
epoll_ctl()
epoll_wait()
int epoll_create(int size);
建立一個epoll的控制代碼。
- 自從linux2.6.8之後,size引數是被忽略的。
- 建立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可以是以下幾個宏的集合:
- EPOLLIN:表示對應的檔案描述符可以讀(包括對端SOCKET正常關閉);
- EPOLLOUT:表示對應的檔案描述符可以寫;
- EPOLLPRI:表示對應的檔案描述符有緊急的資料可讀(這裡應該表示有帶外資料到來);
- EPOLLERR:表示對應的檔案描述符發生錯誤;
- EPOLLHUP:表示對應的檔案描述符被結束通話;
- EPOLLET:將EPOLL設為邊緣觸發(Edge Triggered)模式,這是相對於水平觸發(Level Triggered)來說的。
- EPOLLONESHOT:只監聽一次事件,當監聽完這次事件之後,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL佇列裡。
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
收集在epoll監控的事件中已經發生的事件。
- 引數events是分配好的epoll_event結構體陣列,epoll將會把發生的事件賦值到events陣列中(events不可以是空指標,核心只負責把資料複製到這個events陣列中,不會去幫助我們在使用者態中分配記憶體)。
- maxevents告之核心這個events有多大,這個maxevents的值不能大於建立epoll_create()時的size。(自從linux2.6.8之後,size引數是被忽略的。)maxevents值使用cat /proc/sys/fs/file-max命令查詢,與記憶體的大小有關。
- 最後一個timeout是epoll_wait的超時,為0的時候表示馬上返回,為-1的時候表示一直等下去,直到有事件發生,為任意正整數的時候表示等這麼長的時間,如果一直沒有事件,則返回。一般如果網路主迴圈是單獨的執行緒的話,可以用-1來等,這樣可以保證一些效率,如果是和主邏輯在同一個執行緒的話,則可以用0來保證主迴圈的效率。
- 如果函數呼叫成功,返回對應I/O上已準備好的檔案描述符數目,如返回0表示已超時。
Edge Triggered 工作模式
- epoll工作在ET模式的時候,必須使用非阻塞套介面,以避免由於一個檔案控制代碼的阻塞讀/阻塞寫操作把處理多個檔案描述符的任務餓死。
- 最好以下面的方式呼叫ET模式的epoll介面,在後面會介紹避免可能的缺陷。
@ 基於非阻塞檔案控制代碼
@ 只有當read()或者write()返回EAGAIN時才需要掛起,等待。
但這並不是說每次read()時都需要迴圈讀,直到讀到產生一個EAGAIN才認為此次事件處理完成,當read()返回的讀到的資料長度小於請求的資料長度時,就可以確定此時緩衝中已沒有資料了,也就可以認為此事讀事件已處理完成。
本文永久更新連結地址:http://www.linuxidc.com/Linux/2016-04/129815.htm
相關文章