首页 > 其他分享 >epoll 里面的et, lt

epoll 里面的et, lt

时间:2023-09-13 17:33:21浏览次数:29  
标签:epoll read bytes event lt 事件 et events

在Linux网络编程中,epoll是一种高效的事件驱动I/O多路复用机制,用于管理大量的文件描述符(通常是套接字)并监控它们上的事件。epoll支持两种工作模式:边缘触发(Edge-Triggered,ET)和水平触发(Level-Triggered,LT)。下面我将详细解释这两种模式,并提供示例说明。

  1. 边缘触发(Edge-Triggered,ET):
    • 边缘触发模式仅在文件描述符状态发生变化时通知应用程序。这意味着如果你没有处理所有可用的数据或事件,epoll不会再次通知你,直到下一个状态变化。
    • 用于ET模式的epoll_wait函数仅在文件描述符的状态从不可读/不可写变为可读/可写时返回。
    • ET模式要求应用程序在通知后立即处理数据,以避免遗漏任何事件。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/epoll.h>

int main() {
    int epoll_fd = epoll_create1(0);
    struct epoll_event event;
    event.events = EPOLLIN | EPOLLET; // ET模式
    event.data.fd = STDIN_FILENO; // 监视标准输入

    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, STDIN_FILENO, &event) == -1) {
        perror("epoll_ctl");
        exit(EXIT_FAILURE);
    }

    struct epoll_event events[10];
    while (1) {
        int num_events = epoll_wait(epoll_fd, events, 10, -1);
        if (num_events == -1) {
            perror("epoll_wait");
            exit(EXIT_FAILURE);
        }
        for (int i = 0; i < num_events; i++) {
            if (events[i].data.fd == STDIN_FILENO) {
                // 处理标准输入可读事件
                char buffer[1024];
                ssize_t bytes_read = read(STDIN_FILENO, buffer, sizeof(buffer));
                if (bytes_read == -1) {
                    perror("read");
                    exit(EXIT_FAILURE);
                }
                if (bytes_read == 0) {
                    // EOF,标准输入关闭
                    printf("Standard input closed.\n");
                    exit(EXIT_SUCCESS);
                }
                // 处理读取的数据
                printf("Read %zd bytes: %.*s\n", bytes_read, (int)bytes_read, buffer);
            }
        }
    }
    return 0;
}
View Code

 

  1. 水平触发(Level-Triggered,LT):
    • 水平触发模式在文件描述符上的状态变化仍然有效,但epoll_wait会一直返回,直到描述符上的事件被处理,即使只处理了部分数据。
    • 应用程序需要自己维护事件的状态,以确保所有数据都被处理。

示例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/epoll.h>

int main() {
    int epoll_fd = epoll_create1(0);
    struct epoll_event event;
    event.events = EPOLLIN; // LT模式
    event.data.fd = STDIN_FILENO; // 监视标准输入

    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, STDIN_FILENO, &event) == -1) {
        perror("epoll_ctl");
        exit(EXIT_FAILURE);
    }

    struct epoll_event events[10];
    while (1) {
        int num_events = epoll_wait(epoll_fd, events, 10, -1);
        if (num_events == -1) {
            perror("epoll_wait");
            exit(EXIT_FAILURE);
        }
        for (int i = 0; i < num_events; i++) {
            if (events[i].data.fd == STDIN_FILENO) {
                // 处理标准输入可读事件
                char buffer[1024];
                ssize_t bytes_read = read(STDIN_FILENO, buffer, sizeof(buffer));
                if (bytes_read == -1) {
                    perror("read");
                    exit(EXIT_FAILURE);
                }
                if (bytes_read == 0) {
                    // EOF,标准输入关闭
                    printf("Standard input closed.\n");
                    exit(EXIT_SUCCESS);
                }
                // 处理读取的数据
                printf("Read %zd bytes: %.*s\n", bytes_read, (int)bytes_read, buffer);
            }
        }
    }
    return 0;
}
View Code

总之,

ET模式只在文件描述符状态变化时通知应用程序。

这种模式下,当文件描述符状态发生变化(比如,新的数据到达,或者数据已经被消费)时,epoll_wait()会返回相应的事件。在处理这些事件时,必须要使用非阻塞I/O,否则如果数据没有读或写完,会导致阻塞,进而影响程序效率。

 

LT模式在文件描述符上的事件仍然有效,直到应用程序处理完它们。

这种模式下,当文件描述符状态发生变化,并且这个变化的状态一直保持到epoll_wait()调用时,epoll_wait()才会返回相应的事件。这种模式下,可以使用阻塞I/O

 

选择哪种模式取决于应用程序的需求和设计。

 

 

 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/epoll.h>

int main() {
    // 创建 epoll 实例并获取 epoll 文件描述符
    int epoll_fd = epoll_create1(0);

    // 创建 epoll_event 结构体,用于描述要监视的事件
    struct epoll_event event;
    
    // 设置要监视的事件,这里使用 EPOLLIN 表示可读事件,EPOLLET 表示边缘触发模式
    event.events = EPOLLIN | EPOLLET; // ET模式
    event.data.fd = STDIN_FILENO; // 监视标准输入

    // 将事件添加到 epoll 实例中进行监视
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, STDIN_FILENO, &event) == -1) {
        perror("epoll_ctl");
        exit(EXIT_FAILURE);
    }

    // 创建用于存储触发事件的 epoll_event 数组
    struct epoll_event events[10];
    
    // 进入事件循环
    while (1) {
        // 等待事件发生,epoll_wait 会一直阻塞直到有事件发生或出错
        int num_events = epoll_wait(epoll_fd, events, 10, -1);
        if (num_events == -1) {
            perror("epoll_wait");
            exit(EXIT_FAILURE);
        }
        
        // 处理触发的事件
        for (int i = 0; i < num_events; i++) {
            if (events[i].data.fd == STDIN_FILENO) {
                // 如果事件是标准输入可读事件,进行处理
                
                // 创建缓冲区用于读取数据
                char buffer[1024];
                
                // 读取数据到缓冲区,bytes_read 存储实际读取的字节数
                ssize_t bytes_read = read(STDIN_FILENO, buffer, sizeof(buffer));
                if (bytes_read == -1) {
                    perror("read");
                    exit(EXIT_FAILURE);
                }
                
                // 如果读取到了 EOF,标准输入关闭,退出程序
                if (bytes_read == 0) {
                    printf("Standard input closed.\n");
                    exit(EXIT_SUCCESS);
                }
                
                // 处理读取的数据
                printf("Read %zd bytes: %.*s\n", bytes_read, (int)bytes_read, buffer);
            }
        }
    }
    return 0;
}

 

  • epoll_create1(0) 创建一个 epoll 实例,并返回一个 epoll 文件描述符。
  • struct epoll_event event 创建一个 epoll_event 结构体,用于描述要监视的事件。
  • event.events 设置要监视的事件类型,这里使用 EPOLLIN 表示可读事件和 EPOLLET 表示边缘触发模式。
  • event.data.fd 设置要监视的文件描述符,这里是标准输入。
  • epoll_ctl(epoll_fd, EPOLL_CTL_ADD, STDIN_FILENO, &event) 将事件添加到 epoll 实例中进行监视。
  • epoll_wait(epoll_fd, events, 10, -1) 等待事件发生,一旦有事件发生,它会填充 events 数组并返回触发事件的数量。
  • 在事件循环中,我们遍历 events 数组,检查触发的事件是否是标准输入的可读事件。
  • 如果是标准输入的可读事件,我们创建一个缓冲区 buffer,然后使用 read 函数读取数据到缓冲区。
  • 如果读取到了 EOF,说明标准输入关闭,我们输出消息并退出程序。
  • 否则,我们处理读取到的数据并输出它。

----------------------------------

 

 

在Linux网络编程中,epoll是一种高效的事件驱动I/O多路复用机制,它支持两种工作模式:边缘触发(Edge-Triggered,ET)和水平触发(Level-Triggered,LT)。这两种模式在使用上有一些区别和联系,下面详细解释它们以及各自的应用场景:

  1. 边缘触发(Edge-Triggered,ET):

    • 边缘触发模式只在文件描述符状态发生变化时通知应用程序,而且只通知一次。这意味着如果你没有处理所有可用的数据或事件,epoll不会再次通知你,直到下一个状态变化。
    • 用于ET模式的epoll_wait函数仅在文件描述符的状态从不可读/不可写变为可读/可写时返回。

    应用场景:

    • 高性能场景:适用于高性能网络服务器,因为它要求应用程序在通知后立即处理数据,以避免遗漏任何事件。
    • 高并发场景:ET模式适用于需要处理大量并发连接的服务器,因为它可以有效减少不必要的事件通知,提高性能。
  2. 水平触发(Level-Triggered,LT):

    • 水平触发模式在文件描述符上的状态变化仍然有效,即使状态没有变化,epoll_wait也会一直返回。这意味着如果你没有处理所有可用的数据或事件,epoll_wait会返回,并在下次调用时再次返回。
    • 应用程序需要自己维护事件的状态,以确保所有数据都被处理。

    应用场景:

    • 一般应用场景:LT模式适用于一般的应用程序,因为它的工作方式更容易理解和掌握,不容易出现遗漏事件的情况。
    • 软件可维护性要求较高的场景:LT模式相对容易管理,更容易编写可维护的代码,因为不需要过多关注事件的精确触发。

区别和联系:

  • 主要区别在于事件通知的方式和处理方式。ET模式只通知状态变化,而LT模式通知状态变化和保持通知直到处理完毕。
  • ET模式要求应用程序在每次事件通知后处理所有可用数据,否则可能导致事件丢失。LT模式不会丢失事件,但需要应用程序自己维护事件状态。
  • ET模式通常更高效,因为它减少了事件通知的次数,但要求应用程序高效地处理通知。
  • LT模式相对容易理解和使用,适用于一般的网络编程任务,但可能会产生更多的事件通知。

选择使用哪种模式取决于应用程序的需求和性能要求。在高性能、高并发的场景中,ET模式通常更有优势。在一般应用中,LT模式可能更容易编写和维护。无论使用哪种模式,都需要小心处理事件以确保正确性和性能。

标签:epoll,read,bytes,event,lt,事件,et,events
From: https://www.cnblogs.com/music-liang/p/17700273.html

相关文章

  • .net core(微服务学习)-使用 AgileConfig轻量配置中心
    由于之前项目维护的时候有多个API服务,发布时候又做了高可用多主机均衡负载,环境又有多套,当部署新代码的时候如果有新增配置项需要修改N个环境和服务器实属折磨人    我们知道每个.netcore中都有一个appsettings.json的配置文件,由于之前项目有3个环境,一共有4台主机,每个主......
  • 关于AD原理图中的Floating Net Label错误
    编译之后提示如下:直接双击错误跳转这是说标签浮空,没有连接到导线上这里将导线和电阻重新连接,就解决了报错还有另外一种常见的错误如下:这是标签没有连接到导线上,放大原理图并选中标签,结果如下标签左下角有个十字,必须将它放到导线上,放完之后即可解决问题(如果不好调整可以设置一下栅格......
  • Springboot RocketMQ整合—官方原版
    Doker 技术人自己的数码品牌Doker官网:Doker多克一、添加maven依赖:<dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>${RELEASE.VERSION}</version></dependen......
  • Jmeter BeanShell, 读取HTTP请求返回的JSON,并将其存到文件中
    1、创建BeanShellSampler将fastjson-1.2.30.jar放到Jmeter安装目录\lib下 importjava.io.*;importcom.alibaba.fastjson.JSONObject;importjava.io.IOException;importjava.io.File;importjava.io.FileOutputStream;importjava.io.FileWriter;privatestat......
  • Transformer-empowered Multi-scale Contextual Matching and Aggregation for
    Transformer-empoweredMulti-scaleContextualMatchingandAggregationforMulti-contrastMRISuper-resolution(阅读文献)10.12基于变压器的磁共振多对比度超分辨率多尺度背景匹配与聚合摘要:MRI可以显示相同解剖结构的多对比图像,使多对比超分辨率(SR)技术成为可能。和使用单一......
  • Logstash中Filter的四大插件(grok、date、mutate、mutiline)
    一、grok1.grok使用文本片段切分的方式来切分日志事件filter{grok{match=>{"message"=>"%{IP:client_id_address}%{WORD:method}%{URIPATHPARAM:request}%{NUMBER:bytes}%{NUMBER:http_response_time}"}}}2.内置正则表达式调用%{SYNTAX:SEMANT......
  • VDSR-Accurate Image Super-Resolution Using Very Deep Convolutional Networks阅读
    AccurateImageSuper-ResolutionUsingVeryDeepConvolutionalNetworks(VDSR)阅读笔记(22.10.07)使用深度卷积网络的精确图像超分辨率摘要:使用一个非常深的卷积神经网络,灵感来源于VGG-Net。本文发现,网络深度增加可以显著提高准确性。本文模型最终使用了20个权重层。通过在深度网......
  • VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE
    (VGG)VERYDEEPCONVOLUTIONALNETWORKSFORLARGE-SCALEIMAGERECOGNITION阅读笔记(22.10.05)摘要:本文研究在大规模图像识别设置中卷积网络深度对其准确性的影响。主要贡献是对使用(3,3)卷积核的体系结构增加深度的网络进行全面评估,结果表明,深度推到16-19可以实现对现有技术配置的显......
  • Solution Set - 贪心和数据结构
    感觉自己好菜啊,这个专题真的不太会。CF1439CGreedyShoppingLink&Submission.容易发现,当此人连续买了一段物品之后,他的钱数至少减半。所以他最多只会买\(O(\logV)\)段物品。那么就可以直接模拟每次询问,不断往后轮流找最多能买到的位置和下一个能买的位置。二者都可以线段树......
  • ctfhub---ret2text
    一、程序初步分析 没有开任何保护,64位程序二、IDA反编译 main函数中的gets函数没有对输入限制长度,存在栈溢出 secure函数中出现了system("/bin/sh"),让main函数的返回地址rip指向该函数即可  查看main函数中的输入v4,距离ebp0x70,加上64位ebp共8个字节,覆盖返回地址需......