网络编程:事件模型关于epoll 边缘触发与水平触发的理解

news2024/11/15 15:25:36

文章目录

  • EPOLL事件有两种模型:
    • ET模式
    • LT模式
    • 运行区别
    • 边缘触发的实际使用
    • 代码如下

EPOLL事件有两种模型:

Edge Triggered (ET) 边缘触发只有数据到来才触发,不管缓存区中是否还有数据。
Level Triggered (LT) 水平触发只要有数据都会触发。
(两种触发模式,减少epoll_wait()调用的次数)
Epoll ET非阻塞IO 最优

ET模式

ET模式即Edge Triggered工作模式。
如果我们在第1步将RFD添加到epoll描述符的时候使用了EPOLLET标志,那么在第5步调用epoll_wait之后将有可能会挂起,因为剩余的数据还存在于文件的输入缓冲区内,而且数据发出端还在等待一个针对已经发出数据的反馈信息。只有在监视的文件句柄上发生了某个事件的时候 ET 工作模式才会汇报事件。因此在第5步的时候,调用者可能会放弃等待仍在存在于文件输入缓冲区内的剩余数据。epoll工作在ET模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。最好以下面的方式调用ET模式的epoll接口,在后面会介绍避免可能的缺陷。

  1. 基于非阻塞文件句柄
  2. 只有当read或者write返回EAGAIN(非阻塞读,暂时无数据)时才需要挂起、等待。但这并不是说每次read时都需要循环读,直到读到产生一个EAGAIN才认为此次事件处理完成,当read返回的读到的数据长度小于请求的数据长度时,就可以确定此时缓冲中已没有数据了,也就可以认为此事读事件已处理完成。

LT模式

LT模式即Level Triggered工作模式。
与ET模式不同的是,以LT方式调用epoll接口的时候,它就相当于一个速度比较快的poll,无论后面的数据是否被使用。
LT(level triggered):LT是缺省的工作方式,并且同时支持block和no-block socket。在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表
ET(edge-triggered):ET是高速工作方式,只支持no-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知。请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once).

运行区别

在这里插入图片描述

程序:client向server发送分两次发送buf[10],aaaa\nbbbb\n。write后会停顿5s,两种不同事件的不同如下。

请添加图片描述
在这里插入图片描述
分析:边缘触发,第一次只输出aaaa\n,等到下一次epoll记录到读事件的时候才会发送下一条数据bbbb\n,并且此时缓冲区中会有cccc\ndddd\n数据,时间一长会造成缓冲区数据过多。
水平触发:第一次就发送aaaa\nbbbb\n,有数据就发。

边缘触发的实际使用

(1)server首先接收部分字节,如果不想接收后续的输入,可以使用边缘触发模式【水平触发就做不到】。此时后面的数据还在缓冲区之中。
(2)非阻塞方式:假如需要读的数据读不够n个字节,server会阻塞,epoll不能继续执行,则会产生死锁。此时,需采用epoll非阻塞IO(1.fcntl 2.open)。

代码如下

server.c
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <unistd.h>

#define MAXLINE 10
#define SERV_PORT 9000

int main()
{
    struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd, connfd;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];
    int efd;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    listen(listenfd, 20);

    struct epoll_event event;
    struct epoll_event resevent[10];
    int res, len;

    efd = epoll_create(10);
    // event.events = EPOLLIN;
    event.events = EPOLLIN | EPOLLET; /* ET 边沿触发 */

    printf("Accepting connections ...\n");
    cliaddr_len = sizeof(cliaddr);
    connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
    printf("received from %s at PORT %d\n",
           inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
           ntohs(cliaddr.sin_port));

    event.data.fd = connfd;
    epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &event);

    while (1)
    {
        res = epoll_wait(efd, resevent, 10, -1);
        printf("res %d\n", res);
        if (resevent[0].data.fd == connfd)
        {
            len = read(connfd, buf, MAXLINE / 2);
            write(STDOUT_FILENO, buf, len);
        }
    }

    return 0;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define MAXLINE 10
#define SERV_PORT 9000
int main(int argc, char *argv[])
{
    struct sockaddr_in servaddr;
    char buf[MAXLINE];
    int sockfd, i;
    char ch = 'a';

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);

    connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    while(1)
    {
        for(i = 0;i < MAXLINE / 2;i++)
            buf[i] = ch;
        buf[i-1] = '\n';
        ch++;

        for(;i < MAXLINE;i++)
            buf[i] = ch;
        buf[i-1] = '\n';
        ch++;

        write(sockfd,buf,sizeof(buf));
        sleep(5);
    } 
    close(sockfd);



    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1116567.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【USRP】软件无线电基础篇:长波、中波、短波

一、频率和波长 类型频率波长长波30&#xff5e;300千赫&#xff08;KHz&#xff09;10&#xff5e;1千米中波300&#xff5e;3000千赫&#xff08;KHz&#xff09;10&#xff5e;1百米短波3&#xff5e;30兆赫&#xff08;MHz&#xff09;100&#xff5e;10米 二、传输距离 …

SystemVerilog Assertions应用指南 Chapter 11.5SVA检验器的时序窗口

11.5SVA检验器的时序窗口 到目前为止,带延迟的例子使用的都是固定的正延迟。在下面几个例子中,我们将讨论几种不同的描述延迟的方法属性p12检查布尔表达式“a&&b”在任何给定的时钟上升沿为真。如果表达式为真,那么在接下去的1-~3周期内,信号“c”应该至少在一个时钟周…

蓝桥杯每日一题2023.10.20

题目描述 等差数列 - 蓝桥云课 (lanqiao.cn) 知识点&#xff1a; 排序找出最大公约数则为公差 项数: n (第n项值-首项) / 公差 1。 n (an-a1) / d1 #include<bits/stdc.h> using namespace std; typedef long long ll; const int N 2e5 10; int a[N], n; int gcd…

高复杂度,斐波那契数列

n大的时候&#xff0c;值会很大

java中的容器(集合),HashMap底层原理,ArrayList、LinkedList、Vector区别,hashMap加载因子0.75原因

一、java中的容器 集合主要分为Collection和Map两大接口&#xff1b;Collection集合的子接口有List、Set&#xff1b;List集合的实现类有ArrayList底层是数组、LinkedList底层是双向非循环列表、Vector&#xff1b;Set集合的实现类有HashSet、TreeSet&#xff1b;Map集合的实现…

IoT 物联网共享充电桩场景中设备资产定位和地理围栏开发实践

基于经纬度的设备资产定位和地理围栏在物联网场景中应用广泛 01 物联网 GEO 场景架构方案 首先&#xff0c;IoT 终端设备通过卫星定位模块获取当前经纬度&#xff1b;然后&#xff0c;将坐标信息实时上报到物联网平台&#xff1b;最后&#xff0c;存储到 Redis GEO 数据库中。 …

Golang实现逻辑编排解释引擎

作者&#xff1a;井卓 文章简介&#xff1a; 逻辑编排提供一站式集成平台&#xff0c;简化了在集成接口、应用和服务时&#xff0c;所涉及的业务逻辑和流程。本文会介绍如何通过ChatGPT学习Golang、以及表达式解释器的实现和Golang解析引擎的基本设计架构。 Golang实现逻辑编…

openHarmony UI开发

常用组件和布局方式 组件 ArkUI有丰富的内置组件&#xff0c;包括文本、按钮、图片、进度条、输入框、单选框、多选框等。和布局一样&#xff0c;我们也可以将基础组件组合起来&#xff0c;形成自定义组件。 按钮&#xff1a; Button(Ok, { type: ButtonType.Normal, stateEf…

Git 安装和基础命令、IDEA 基础操作

目录 总结命令&#xff1a;1、安装&#xff1a;1、安装2、配置环境变量&#xff1a; 2、Git操作&#xff1a;1、初始化&#xff1a;1、姓名邮箱&#xff1a;2、初始化仓库&#xff1a;3、工作区和暂存区分析 2、提交文件3、查看版本库状态4、安装小乌龟git不显示图标 5、查看提…

Redis常用配置详解

目录 一、Redis查看当前配置命令二、Redis基本配置三、RDB全量持久化配置&#xff08;默认开启&#xff09;四、AOF增量持久化配置五、Redis key过期监听配置六、Redis内存淘汰策略七、总结 一、Redis查看当前配置命令 # Redis查看当前全部配置信息 127.0.0.1:6379> CONFIG…

微信小程序之会议OA首页数据交互,会议状态,会议人数转换,会议室交互,WXS的使用

前言&#xff1a; 本篇博客使用结合了SpringMVC&#xff0c;mybatis&#xff0c;maven&#xff0c;小程序&#xff0c;如果不熟悉使用可以翻看我之前的博客&#xff0c;以便大家可以更好的学习&#xff01;&#xff01;&#xff01; 一&#xff0c;会议OA首页数据的后台交互 这…

18、监测数据采集物联网应用开发步骤(12.3)

阶段性源码下载 监测数据采集物联网应用开发步骤(12.2) 前端web UI开发 demo 核心代码文件&#xff1a; web/index.html web/index.js web/js/common.js web/init.dlls Web/init.js 程序运行之后在浏览器敲入如下内容访问数据接口&#xff1a; http://localhost:9000…

五大经典智能算法实现机器人路径规划,包含简单路径与复杂路径,详细对比实验...

声明&#xff1a;对于作者的原创代码&#xff0c;禁止转售倒卖&#xff0c;违者必究&#xff01; 本期文章采用五大经典的智能优化算法&#xff0c;对机器人路径进行规划。 五大经典算法分别是&#xff1a;粒子群算法(PSO)&#xff0c;遗传算法(GA)&#xff0c;差分进化算法(DE…

马赫数相关函数

1 函数 k是常数&#xff0c;Ma是变量 2应用程序 点击上方资源下载 3 计算 3.1 c语言 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <math.h>#define k 1.4 // k为常数// 定义的函数 double T(double Ma) {return pow((1 (k - 1) / 2 * Ma …

npm或pnpm终端执行失败问题

问题描述&#xff1a; npm或pnpm终端执行失败问题&#xff1a;有时候在编译器中通过包管理工具进行某些命令操作时&#xff0c;会提示如下报错 pnpm : 无法加载文件 E:\1AllLearnSource\nvm\node\pnpm.ps1&#xff0c;因为在此系统上禁止运行脚本。有关详细信息&#xff0c;…

使用imx 8m 测试matter协议功能

参考网址&#xff1a; https://github.com/nxp-imx/meta-matter 请使用Ubuntu-20.04。18.04python版本太老 注意repo会出现此报错&#xff0c;可以无视&#xff1a; git checkout imx_matter_2023_q3 这一步在这个目录下操作 项目交流、学习、开发&#xff0c;欢迎私信。

【大数据】Kafka 数据存储

Kafka 数据存储 1.文件目录2.日志分段3.日志索引3.1 偏移量索引3.2 时间戳索引 4.日志清理4.1 日志删除4.1.1 基于时间4.1.2 基于日志大小4.1.3 基于日志起始偏移量 4.2 日志压缩 1.文件目录 Kafka 中的消息是存储在磁盘上的&#xff0c;一个分区副本对应一个 日志&#xff08…

2019年亚太杯APMCM数学建模大赛A题基于图像分析的二氧化硅熔化表示模型求解全过程文档及程序

2019年亚太杯APMCM数学建模大赛 A题 基于图像分析的二氧化硅熔化表示模型 原题再现 铁尾矿的主要成分是二氧化硅&#xff0c;而二氧化硅是铁尾矿成分中最难熔化的部分。因此&#xff0c;铁尾矿的熔融行为可以用二氧化硅的熔融行为来表示。然而&#xff0c;高温熔池的温度超过…

AIO开放接口平台免费畅享ChatGPT聊天、联网互动、学术等服务!更有DALL·E 3最强AI绘图功能!

免费畅享&#xff01; AIO平台ChatGPT联网、聊天、学术等服务&#xff01; AIO开放接口平台 | 服务介绍 ALL IN ONE &#xff08;AIO&#xff09;API服务是LLM(大语言模型)开放接口平台&#xff1a;持续接入各种主流的大模型接口&#xff0c;并提供简单、易用、统一的API交互…

开源网安受邀参加数字安全高峰论坛,为数字经济发展保驾护航

​10月19日&#xff0c;“提升数字安全技术&#xff0c;护航数字经济发展”高峰论坛在常州创意产业园圆满完成。本次论坛由常州国家高新区管委会、常州市工业和信息化局、常州市大数据管理中心主办&#xff0c;聚焦“数据安全”主题&#xff0c;邀请了超百位专家及企业代表共同…