一、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;
}