前言
本篇文章主要来讲解epoll的ET模式和LT模式,epoll中有两种模式可以选择一种是ET模式(边缘触发模式),另一种是LT模式(水平触发模式)
一、ET模式和LT模式概念讲解
1.水平触发模式(LT,Level-Triggered)
在水平触发模式下,当一个文件描述符上的I/O事件就绪时,epoll会立即通知应用程序,然后应用程序可以对就绪事件进行处理。即,只要文件描述符处于就绪状态,epoll就会持续通知应用程序,直到应用程序处理完所有就绪事件并且再次进入阻塞等待状态。
对于非阻塞I/O,如果一个文件描述符上有可读或可写事件发生,应用程序可以立即进行读或写操作,即使读写操作无法一次完成。如果读或写操作不能立即完成,应用程序可以再次调用epoll等待新的事件通知。
2.边缘触发模式(ET,Edge-Triggered)
在边缘触发模式下,当一个文件描述符上的状态发生变化时(例如从不可读变为可读,或者从不可写变为可写),epoll会通知应用程序。
与水平触发模式不同的是,边缘触发模式只在状态变化的瞬间通知应用程序,通知仅发送一次。如果应用程序没有及时处理完这个事件,下次等待时将会错过该事件,即使事件仍然处于就绪状态。因此,在边缘触发模式下,应用程序需要确保尽可能完整地处理每个事件,以避免遗漏事件。
边缘触发模式适用于需要及时响应状态变化的场景,通常可以提供更高的性能,因为它最大程度上减少了不必要的事件通知。
二、边缘触发和水平触发适用的场景
边缘触发(ET)模式适用的情况:
需要尽快处理就绪事件:边缘触发模式通知应用程序文件描述符状态发生变化的时刻,要求应用程序立即对就绪事件进行处理。适用于需要高精度的事件处理,减少事件丢失的情况。
非阻塞I/O操作:边缘触发模式对非阻塞I/O操作更加高效,适用于需要按需处理大量数据的情况。
#include <stdio.h>
#include <sys/epoll.h>
#include <fcntl.h> // 包含非阻塞I/O所需的头文件
int main() {
int epoll_fd = epoll_create1(0);
struct epoll_event event;
struct epoll_event events[10]; // 用于存储事件的数组
// 向epoll实例注册文件描述符和事件
event.events = EPOLLIN | EPOLLET; // 边缘触发模式
event.data.fd = 0; // 示例中使用标准输入的文件描述符
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, 0, &event) == -1) {
perror("Failed to add file descriptor to epoll");
return -1;
}
// 设置标准输入为非阻塞模式
int flags = fcntl(0, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(0, F_SETFL, flags);
// 等待事件发生
while (1) {
int num_events = epoll_wait(epoll_fd, events, 10, -1);
if (num_events == -1) {
perror("Failed to wait for events");
return -1;
}
for (int i = 0; i < num_events; i++) {
if (events[i].data.fd == 0) {
// 标准输入有数据可读
char buffer[100];
ssize_t num_bytes = read(0, buffer, sizeof(buffer));
if (num_bytes > 0) {
// 处理读取的数据
// ...
}
}
}
}
return 0;
}
水平触发(LT)模式适用的情况:
需要持续处理就绪事件:水平触发模式会持续通知应用程序文件描述符就绪,直到应用程序处理完所有就绪事件。适用于需要处理多个相关事件或者需要一次性处理大量数据的情况。
阻塞和非阻塞I/O操作混合使用:水平触发模式适用于既有阻塞又有非阻塞I/O操作的情况,可以在阻塞操作中循环调用读取或写入操作。文章来源:https://www.toymoban.com/news/detail-660710.html
#include <stdio.h>
#include <sys/epoll.h>
int main() {
int epoll_fd = epoll_create1(0);
struct epoll_event event;
struct epoll_event events[10]; // 用于存储事件的数组
// 向epoll实例注册文件描述符和事件
event.events = EPOLLIN; // 水平触发模式(默认模式)
event.data.fd = 0; // 示例中使用标准输入的文件描述符
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, 0, &event) == -1) {
perror("Failed to add file descriptor to epoll");
return -1;
}
// 等待事件发生
while (1) {
int num_events = epoll_wait(epoll_fd, events, 10, -1);
if (num_events == -1) {
perror("Failed to wait for events");
return -1;
}
for (int i = 0; i < num_events; i++) {
if (events[i].data.fd == 0) {
// 标准输入有数据可读
char buffer[100];
ssize_t num_bytes = read(0, buffer, sizeof(buffer));
// 处理读取的数据
// ...
}
}
}
return 0;
}
总结
本篇文章就讲解到这里。文章来源地址https://www.toymoban.com/news/detail-660710.html
到了这里,关于Linux网络编程(epoll的ET模式和LT模式)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!