epoll学习
- struct epoll_event
结构体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 event / epoll_data_t data; / User data variable */ };
其中events表示感兴趣的事件和被触发的事件,可能的取值为: EPOLLIN:表示对应的文件描述符可以读; EPOLLOUT:表示对应的文件描述符可以写; EPOLLPRI:表示对应的文件描述符有紧急的数可读;
EPOLLERR:表示对应的文件描述符发生错误; EPOLLHUP:表示对应的文件描述符被挂断; EPOLLET: ET的epoll工作模式;
所涉及到的函数有:
1、epoll_create函数 函数声明:int epoll_create(int size)
功能:该函数生成一个epoll专用的文件描述符,其中的参数是指定生成描述符的最大范围;
2、epoll_ctl函数 函数声明:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) 在epfd上注册一个fd-events, 监听event->events的事件类型
功能:用于控制某个文件描述符上的事件,可以注册事件,修改事件,删除事件。
@epfd:由epoll_create生成的epoll专用的文件描述符;
@op:要进行的操作,EPOLL_CTL_ADD注册、EPOLL_CTL_MOD修改、EPOLL_CTL_DEL删除;
@fd:关联的文件描述符;
@event:指向epoll_event的指针;
成功:0;失败:-1
3、epoll_wait函数 函数声明:int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)
功能:该函数用于轮询I/O事件的发生;
@epfd:由epoll_create生成的epoll专用的文件描述符;
@epoll_event:用于回传代处理事件的数组;
@maxevents:每次能处理的事件数;
@timeout:等待I/O事件发生的超时值;
成功:返回发生的事件数;失败:-1
epoll_ctl
是用于控制 epoll 实例的系统调用之一,它用于向 epoll 实例注册或删除事件,并指定相应的文件描述符和事件类型。
epoll_ctl
的原型如下:
cCopy code
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
其中参数的含义如下:
-
epfd
:epoll 实例的文件描述符,通过epoll_create
创建得到。 -
op
:操作类型,可以是以下几种值之一:
EPOLL_CTL_ADD
:添加一个新的文件描述符到 epoll 实例中。EPOLL_CTL_MOD
:修改一个已注册的文件描述符的事件类型。EPOLL_CTL_DEL
:从 epoll 实例中删除一个文件描述符。
-
fd
:要添加、修改或删除的文件描述符。 -
event
:一个指向struct epoll_event
结构体的指针,用于描述要注册的事件类型和相关的数据。
struct epoll_event
结构体定义如下:
cCopy code
解释struct epoll_event {
uint32_t events; // 事件类型,可以是 EPOLLIN、EPOLLOUT、EPOLLERR 等
epoll_data_t data; // 事件关联的数据,通常是一个联合体
};
epoll_ctl
的主要作用是管理 epoll 实例中的文件描述符和事件,可以添加、修改或删除特定的文件描述符以及相应的事件类型。通过这个系统调用,可以实现高效的 I/O 多路复用机制,使得应用程序能够监视多个文件描述符上的事件,并在事件发生时做出相应的处理。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/epoll.h>
#define MAX_EVENTS 10
int main() {
int epoll_fd, nfds, i;
struct epoll_event event, events[MAX_EVENTS];
// 创建 epoll 实例
epoll_fd = epoll_create1(0);
if (epoll_fd == -1) {
perror("epoll_create1");
exit(EXIT_FAILURE);
}
// 打开一个文件描述符(这里以标准输入描述符为例)
int stdin_fd = STDIN_FILENO;
// 配置要监听的事件
event.events = EPOLLIN; // 监听读事件
event.data.fd = stdin_fd; // 将标准输入描述符与事件关联
// 将事件添加到 epoll 实例中
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, stdin_fd, &event) == -1) {
perror("epoll_ctl: EPOLL_CTL_ADD");
close(epoll_fd);
exit(EXIT_FAILURE);
}
// 等待事件发生
while (1) {
nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_wait");
close(epoll_fd);
exit(EXIT_FAILURE);
}
// 处理所有发生的事件
for (i = 0; i < nfds; ++i) {
if (events[i].events & EPOLLIN) {
printf("Event on file descriptor %d: EPOLLIN\n", events[i].data.fd);
// 从标准输入读取数据并进行处理
char buffer[1024];
ssize_t bytes_read = read(events[i].data.fd, buffer, sizeof(buffer));
if (bytes_read == -1) {
perror("read");
close(epoll_fd);
exit(EXIT_FAILURE);
}
// 处理读取的数据
// ...
}
}
}
// 关闭 epoll 实例
close(epoll_fd);
return 0;
}