一、epoll函數族
1. 函數epoll_creat:?該函數生成一個epoll專用的文件描述符
#include <sys/epoll.h>
int epoll_creae(int size); //epoll上能關注的最大描述符數
?
2.?epoll_ctl:用于控制某個epoll文件描述符事件,可以注冊、修改、刪除
#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
參數:
- efd:epoll_create函數的返回值
- op:對該監聽紅黑樹所做操作
- fd:待監聽的fd
- event:struct epoll_event 結構體
typedef union epoll_data
{void* ptr;int fd; //對應監聽的fduint32_t u32;uint64_t u64;
} epoll_data_t;struct epoll_event
{uint32_t events; /* epoll事件 */epoll_data_t data; /* 用戶數據 */
};
?
3.?等待IO事件發生 - 可以設置阻塞的函數
#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
參數:
- efds:epoll_create函數的返回值
- events:傳出參數【數組】滿足監聽條件的哪些fd結構體
- maxevents:數組元素的總個數(1024) struct epoll_events [1024]:
?
二、LT和ET模式
epoll對文件描述符的操作方式有兩種工作模式:LT模式(Level Trigger,水平觸發) 和ET模式(Edge?Trigger,邊緣觸發)。
- ?LT模式:當epoll_wait檢測到其上有事件發生并將此事件通知應用程序后,應用程序可以不立即處理該事件,這樣,當應用程序下一次調用epoll_wait時,epoll_wait還會向應用程序通告此事件,直到該事件被處理。((緩沖區剩余未讀盡的數據會導致epoll_wait返回. )
- ET模式:當epoll_wait檢測到其上有事件發生并將此事件通知應用程序后,應用程序必須立即處理該事件,因為后續的epoll_wait調用將不在向應用程序通告此事件。
1. 水平觸發
?對于讀操作
- 只要緩沖內容不為空,LT模式返回讀就緒。
?對于寫操作
- 只要緩沖區還不滿,LT模式會返回寫就緒。
2. 邊緣觸發
?對于讀操作
- 當緩沖區由不可讀變為可讀的時候,即緩沖區由空變為不空的時候。
- 當有新數據到達時,即緩沖區中的待讀數據變多的時候。
- 當緩沖區有數據可讀,且應用進程對相應的描述符進行EPOLL_CTL_MOD 修改EPOLLIN事件時。
對于寫操作
- 當緩沖區由不可寫變為可寫時。
- 當有舊數據被發送走,即緩沖區中的內容變少的時候。
- 當緩沖區有空間可寫,且應用進程對相應的描述符進行EPOLL_CTL_MOD 修改EPOLLOUT事件時。
三、代碼清單
1. 測試代碼
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <errno.h>
#include <unistd.h>#define MAXLINE 10int main(int argc, char *argv[])
{int efd, i;int pfd[2];pid_t pid;char buf[MAXLINE], ch = 'a';pipe(pfd);pid = fork();if (pid == 0) //子寫{ close(pfd[0]);while (1) { for (i = 0; i < MAXLINE/2; i++) //aaaa\nbuf[i] = ch;buf[i-1] = '\n';ch++;for (; i < MAXLINE; i++) //bbbb\nbuf[i] = ch;buf[i-1] = '\n';ch++;write(pfd[1], buf, sizeof(buf)); //aaaa\nbbbb\nsleep(5);}close(pfd[1]);} else if (pid > 0) //父讀{ struct epoll_event event;struct epoll_event resevent[10]; //epoll_wait就緒返回eventint res, len;close(pfd[1]);efd = epoll_create(10);event.events = EPOLLIN | EPOLLET; // ET 邊沿觸發//event.events = EPOLLIN; // LT 水平觸發 (默認)event.data.fd = pfd[0];epoll_ctl(efd, EPOLL_CTL_ADD, pfd[0], &event);while (1) {res = epoll_wait(efd, resevent, 10, -1);printf("res %d\n", res);if (resevent[0].data.fd == pfd[0]) {len = read(pfd[0], buf, MAXLINE/2);write(STDOUT_FILENO, buf, len);}}close(pfd[0]);close(efd);} else {perror("fork");exit(-1);}return 0;
}
?
?
?
?
- ?