tk_epoll_add函數定義於epoll.c:
int tk_epoll_add(int epoll_fd, int fd, tk_http_request_t* request, int events) {
struct epoll_event event;
event.data.ptr = (void*)request;//初始化事件地址,在webserver中是一個http請求
event.events = events;//events傳入幾個宏的集合,表示epoll感興趣的事件
int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event);//註冊監聽描述符
if (ret == -1)
return -1;
}
該函數在main.c中的調用如下:
tk_epoll_add(epoll_fd, listen_fd, request, (EPOLLIN | EPOLLET));
功能:註冊監聽描述符
傳入的fd爲listen_fd,即註冊監聽描述符。
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 */
};
event.events可以是以下幾個宏的集合:
EPOLLIN :表示對應的文件描述符可以讀(包括對端SOCKET正常關閉);
EPOLLOUT:表示對應的文件描述符可以寫;
EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這裏應該表示有帶外數據到來);
EPOLLERR:表示對應的文件描述符發生錯誤;
EPOLLHUP:表示對應的文件描述符被掛斷;
EPOLLET: 將EPOLL設爲邊緣觸發(Edge Triggered)模式,這是相對於水平觸發(Level Triggered)來說的;
EPOLLONESHOT:只監聽一次事件,當監聽完這次事件之後,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL隊列裏。
因此,傳入本函數的第四個參數 EPOLLIN | EPOLLET 實際上做了兩件事:
1、該fd對應的文件描述符可以讀
2、將EPOLL設置爲ET模式
epoll_ctl函數:
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epoll的事件註冊函數,它不同與select()是在監聽事件時告訴內核要監聽什麼類型的事件,而是在這裏先註冊要監聽的事件類型。第一個參數是epoll_create()的返回值,第二個參數表示動作,用三個宏來表示:
EPOLL_CTL_ADD:註冊新的fd到epfd中;
EPOLL_CTL_MOD:修改已經註冊的fd的監聽事件;
EPOLL_CTL_DEL:從epfd中刪除一個fd;
第三個參數是需要監聽的fd,第四個參數是告訴內核需要監聽什麼事件。