Linux network programming (ET mode and LT mode of epoll)


Preface

This article mainly explains the ET mode and LT mode of epoll. There are two modes to choose from in epoll. One is ET mode (edge ​​trigger mode) and the other is LT mode (horizontal trigger mode).

1. Explanation of the concepts of ET mode and LT mode

1. Horizontal trigger mode (LT, Level-Triggered)

In horizontal trigger mode, when an I/O event on a file descriptor is ready, epoll will immediately notify the application, and then the application can handle the ready event. That is, as long as the file descriptor is in the ready state, epoll will continue to notify the application until the application has processed all ready events and entered the blocking wait state again.

对于非阻塞I/O,如果一个文件描述符上有可读或可写事件发生,应用程序可以立即进行读或写操作,即使读写操作无法一次完成。如果读或写操作不能立即完成,应用程序可以再次调用epoll等待新的事件通知。

2. Edge-triggered mode (ET, Edge-Triggered)

In edge-triggered mode, epoll notifies the application when the state on a file descriptor changes (such as from unreadable to readable, or from unwritable to writable).
Different from the horizontal trigger mode, the edge trigger mode only notifies the application at the moment of state change, and the notification is only sent once. If the application does not handle this event in time, it will miss the event the next time it waits, even if the event is still in the ready state. Therefore, in edge-triggered mode, applications need to ensure that each event is processed as completely as possible to avoid missing events.

边缘触发模式适用于需要及时响应状态变化的场景,通常可以提供更高的性能,因为它最大程度上减少了不必要的事件通知。

2. Applicable scenarios for edge triggering and horizontal triggering

边缘触发(ET)模式适用的情况:

Ready events need to be processed as soon as possible: The edge trigger mode notifies the application of the moment when the file descriptor status changes and requires the application to process the ready event immediately. It is suitable for event processing that requires high precision and reduces event loss.
Non-blocking I/O operations: Edge-triggered mode is more efficient for non-blocking I/O operations and is suitable for situations where large amounts of data need to be processed on demand.

#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)模式适用的情况:

Requires continuous processing of ready events: Horizontal trigger mode continues to notify the application that the file descriptor is ready until the application has processed all ready events. It is suitable for situations where multiple related events need to be processed or a large amount of data needs to be processed at one time.
Mixed use of blocking and non-blocking I/O operations: The horizontal trigger mode is suitable for situations where there are both blocking and non-blocking I/O operations, and read or write operations can be called cyclically in blocking operations.

#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;
}

Summarize

This article will explain it here.

Guess you like

Origin blog.csdn.net/m0_49476241/article/details/132380734