epoll进阶

        epoll除了提供select/poll那种IO事件的电平触发(Level Triggered)外,还提供了边沿触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。

【epoll为什么要有EPOLLET触发模式?】:

        如果采用EPOLLLT模式的话,系统中一旦有大量你不需要读写的就绪文件描述符,它们每次调用epoll_wait都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率.。而采用EPOLLET这种边缘触发模式的话,当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符。 

 事件模型

EPOLL事件有两种模型:

        Edge Triggered (ET) 边缘触发只有数据到来才触发,不管缓存区中是否还有数据。

        Level Triggered (LT) 水平触发只要有数据都会触发。

LT是默认的模式,ET是“高速”模式

        LT(水平触发)模式下,只要这个文件描述符还有数据可读,每次 epoll_wait都会返回它的事件,提醒用户程序去操作;

        ET(边缘触发)模式下,在它检测到有 I/O 事件时,通过 epoll_wait 调用会得到有事件通知的文件描述符,对于每一个被通知的文件描述符,如可读,则必须将该文件描述符一直读到空,让 errno 返回 EAGAIN 为止,否则下次的 epoll_wait 不会返回余下的数据,会丢掉事件。如果ET模式不是非阻塞的,那这个一直读或一直写势必会在最后一次阻塞

案例一:基于管道epoll ET/LT 触发模式 

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

#define MAXLINE 10

int main(int argc, char *argv[])
{
    int efd, i;
    int pfd[2];
    pid_t pid;
    char buf[MAXLINE], ch = 'a';

    pipe(pfd);
    pid = fork();

    if (pid == 0) {             //子 写
        close(pfd[0]);
        while (1) {
            //aaaa\n
            for (i = 0; i < MAXLINE/2; i++)
                buf[i] = ch;
            buf[i-1] = '\n';
            ch++;
            //bbbb\n
            for (; i < MAXLINE; i++)
                buf[i] = ch;
            buf[i-1] = '\n';
            ch++;
            //aaaa\nbbbb\n
            write(pfd[1], buf, sizeof(buf));
            sleep(5);
        }
        close(pfd[1]);

    } else if (pid > 0) {       //父 读
        struct epoll_event event;
        struct epoll_event resevent[10];        //epoll_wait就绪返回event
        int res, len;

        close(pfd[1]);
        efd = epoll_create(10);

        event.events = EPOLLIN | EPOLLET;     // ET 边沿触发
       // event.events = EPOLLIN;                 // LT 水平触发 (默认)
        event.data.fd = pfd[0];
        epoll_ctl(efd, EPOLL_CTL_ADD, pfd[0], &event);

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

        close(pfd[0]);
        close(efd);

    } else {
        perror("fork");
        exit(-1);
    }

    return 0;
}

案例二:基于网络C/S模型的epoll ET触发模式(过渡案例,一般不这么写

如果ET模式不是非阻塞的,那这个一直读或一直写势必会在最后一次阻塞。

ET模式 只支持 非阻塞模式

/* block_epoll_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(void)
{
    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 | EPOLLET;     /* ET 边沿触发, 默认 LT 水平触发 */


    printf("Accepting connections ...\n");

    cliaddr_len = sizeof(cliaddr);
    connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);//自己建立连接,不用监听listenfd了
    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) {

        //如果ET模式不是非阻塞的,那这个一直读或一直写势必会在最后一次阻塞(阻塞在epoll_wait)。
        res = epoll_wait(efd, resevent, 10, -1); //只监听cfd

        printf("res %d\n", res);
		
        if (resevent[0].data.fd == connfd) {

            //如果ET模式不是非阻塞的,那这个一直读或一直写势必会在最后一次阻塞。(阻塞在epoll_wait)
            len = read(connfd, buf, MAXLINE/2);         //readn(500)   
            write(STDOUT_FILENO, buf, len);
        }
    }

    return 0;
}

案例三:基于网络C/S非阻塞模型的epoll ET触发模式(重)

 ET模式 只支持 非阻塞模式

/* noblock_epoll_server.c */
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <fcntl.h>

#define MAXLINE 10
#define SERV_PORT 8000

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

    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 res_event[10];
    int res, len;

    efd = epoll_create(10);

    event.events = EPOLLIN | EPOLLET;     /* ET 边沿触发,默认是水平触发 */

    //event.events = EPOLLIN;
    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));

    flag = fcntl(connfd, F_GETFL);        /* 修改connfd为非阻塞读 */ //是指所读套接字变为非阻塞
    flag |= O_NONBLOCK;
    fcntl(connfd, F_SETFL, flag);

    event.data.fd = connfd;
    epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &event);    //将connfd加入监听红黑树 //是指所读套接字变为非阻塞
	
    while (1) {
        printf("epoll_wait begin\n");
        res = epoll_wait(efd, res_event, 10, -1);        //最多10个, 阻塞监听
        printf("epoll_wait end res %d\n", res);

        if (res_event[0].data.fd == connfd) {
            while ((len = read(connfd, buf, MAXLINE/2)) >0 )    //非阻塞读, 轮询
                write(STDOUT_FILENO, buf, len);
        }
    }

    return 0;
}
/* client.c */
#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) {
        //aaaa\n
        for (i = 0; i < MAXLINE/2; i++)
            buf[i] = ch;
        buf[i-1] = '\n';
        ch++;
        //bbbb\n
        for (; i < MAXLINE; i++)
            buf[i] = ch;
        buf[i-1] = '\n';
        ch++;
        //aaaa\nbbbb\n
        write(sockfd, buf, sizeof(buf));
        sleep(5);
    }
    close(sockfd);

    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Cocos Creator 如何处理物理和碰撞检测?

Cocos Creator 如何处理物理和碰撞检测&#xff1f; cocos creator 版本:v3.6.1 Cocos Creator 3.x 实现碰撞检测 Cocos Creator 通过使用物理引擎来处理物理和碰撞检测。Cocos Creator 默认使用 Box2D 物理引擎&#xff0c;也支持使用 Chipmunk 物理引擎。以下是处理物理和碰撞…

Systemverilog中interprocess间synchronization和communication的记录

1. 同步和通讯机制的种类 systemverilog提供了三种方式&#xff1a;named event type(->, )、semaphore、mailbox。其中semaphores和mailbox虽然是built-in type&#xff0c;但它们是class&#xff0c;且可以作为base classes被扩展为更高level的class。这些built-in class…

VScode配置8086汇编环境

目录 0、感慨 1、VScode的安装 2、下载MASM/TASM插件 3、测试汇编环境 新建文件 汇编文件配置 汇编代码的运行 0、感慨 搭配一个简单些的环境&#xff0c;对于我们汇编的学习很有帮助&#xff0c;在这里又不得不感叹vscode的强大&#xff0c;使用VScodeMASM/TASM插件就…

ChatGPT入门必知必会

2023年是真正意义上的AI之年&#xff0c;因为ChatGPT 2007年&#xff0c;iPhone开启了智能手机时代&#xff0c;2023年&#xff0c;我们迎来了人工智能时代&#xff0c;我们正处于历史的大转折点上&#xff0c;这也许是启蒙运动级别的思想和社会转折&#xff0c;工业革命级别的…

关于“复活节Easter”知识,你了解多少?

复活节是基督教纪念耶稣复活的节日。耶稣被钉死在十字架上&#xff0c;死后第三天复活。Christians say Jesus died on Friday. On the third day, he rose from the dead. He became alive again. 复活节定在每年春分月圆之后第一个星期日举行。因为春分之后日照时间比较长&am…

NumPy 秘籍中文第二版:一、使用 IPython

原文&#xff1a;NumPy Cookbook - Second Edition 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 在本章中&#xff0c;我们将介绍以下秘籍&#xff1a; 安装 IPython使用 IPython 作为 Shell阅读手册页安装 matplotlib运行 IPython 笔记本导出 IPython 笔记本导入网…

GPT、科技、人类的生产、知识与未来(上)

本文将继续结合GPT探讨人工智能技术升级可能对人类社会带来的影响。主要还是侧重历史、社会、文化、经济、政治等角度。 问题的提出&#xff1a;ChatGPT等工具会提高人的工作效率和产出。但它会让人类使用者自身变得更“聪明”&#xff0c;还是“更笨”&#xff1f;更“强”&am…

8个商用图片素材库,你一定要收藏

在日常生活中&#xff0c;经常需要用到图片素材&#xff0c;但很多图片是有版权的&#xff0c;使用不当就会造成侵权。如何找到既能免费下载还能商用的图片素材呢~下面我就要把我收藏多年的商用图片素材网分享出来&#xff0c;希望对大家有帮助&#xff01; 1、菜鸟图库 https…

ROS如何进行开发?

文章目录0、引言1、安装ROS2、ROS创建工作空间和功能包3、在ROS中使用C代码4、在ROS中使用Python代码0、引言 笔者研究生的课题是关于多传感器数据融合的&#xff0c;传感器数据获取一般是通过Arduino或者树莓派获取&#xff0c;Arduino主要偏硬件开发&#xff0c;一般数据处理…

sql语法:详解DDL

Mysql版本&#xff1a;8.0.26 可视化客户端&#xff1a;sql yog 目录一、DDL是什么&#xff1f;二、和数据库相关的DDL2.1 创建数据库2.2 删除数据库2.3 查看所有的数据库&#xff0c;当前用户登录后&#xff0c;可以看到哪些数据库2.4 查看某个数据库的详细定义2.5 修改数据库…

在深圳做了5年软件测试,到头来啥也不是~

本科非计算机专业&#xff0c;在深圳做了5年软件测试工作&#xff0c;从一开始一脸懵的点点点&#xff0c;到现在会自动化测试了&#xff0c;浅谈一下从事软件测试的一点点心得体会&#xff0c;仅供参考交流。如果你本科且非计算机专业的话可以试下&#xff08;但就目前环境建议…

谈一谈Java的ThreadLocal

目录 先说原理&#xff1a; 再上代码&#xff1a; 运行结果&#xff1a; 先说原理&#xff1a; ThreadLocal 是一个本地线程副本变量工具类&#xff0c;它可以在每个线程中创建一个副本变量&#xff0c;每个线程可以独立地修改自己的副本变量&#xff0c;而不会影响其他线程…

测试的价值不仅仅是找

测试的价值不仅仅是找Bug 在我测试工作的前5年&#xff0c;一直以为测试的目标和价值就是在黑盒测试活动中找bug&#xff0c;以找到bug越多越自豪。但当我随着商业意识的不断积累&#xff0c;跳出测试的视角&#xff0c;站在公司的角度看测试时&#xff0c;会发现测试的目标是商…

linux驱动学习加强版-5(ioctl的使用)

文章目录一、添加ioctl控制节点二、修改测试APP2.1 测试APP的代码&#xff1a;2.2 驱动代码&#xff1a;ioctl是用户空间和内核空间相互交流时候用的比较多的一种手段。我们也可以在HAL层通过ioctl调到驱动里面。一、添加ioctl控制节点 先看patch 吧 这是在驱动中添加的ioct…

个人-计算机操作系统第五章

第五章 虚拟存储器 一、章节练习 1.系统抖动是指( )。 A. 使用机器时&#xff0c;千万屏幕闪烁的现象 B. 刚被调出的页面又立刻被调入所形成的频繁调入调出现象 C. 系统盘不净&#xff0c;千万系统不稳定的现象 D. 由于内存分配不当&#xff0c;偶然造成内存不够…

02-神经网络基础

一、从机器学习到神经网络 1. 两层神经网络 - 多层感知机 2. 浅层神经网络特点 (1)需要数据量小、训练速度快; (2)对复杂函数的表示能力有限,泛化能力受到制约。 Kurt Hornik 证明了理论上两层神经网络足以拟合任意函数,而且过去没有足够的数据和计算能力,因此之前的…

兰伯特光照模型(Lambert Lighting)和半兰伯特光照模型(Half-Lanbert)

关于漫反射 光打到凹凸不平的平面上&#xff0c;光线会被反射到四面八方&#xff0c;被称为漫反射 关于这种模型&#xff0c;由于光线由于分散&#xff0c;所以进入人眼的光线强度和观察角度没有区别 在A点和B点接收到的光线强度是一样的 在漫反射下&#xff0c;光线强度只和光…

卫龙携手契约锁,推动人事、采购、销售业务电子签

知名辣味休闲食品企业——卫龙&#xff0c;携手契约锁就印章管控及电子签章技术展开合作&#xff0c;打造覆盖总部及20多家子公司的印章管控平台&#xff0c;以现有泛微OA、钉钉APP为基础&#xff0c;推动人事、采购、销售业务电子签&#xff0c;通过签字、盖章无纸化&#xff…

使用Navicat进行ssh通道连接MySQL数据库

1、正常打开连接窗口&#xff0c;选择SSH&#xff1b; 2、填写完SSH对应参数&#xff0c;重新选择常规&#xff1b; SSH参数&#xff1a; 主机 > 服务器IP 端口 > 22 【一般22&#xff0c;SSH监听端口】 用户名 > 登录服务器账户 密码 > 登录服务器密码常规的参数…

mplfinancet绘制K线图

mplfinancet绘制K线图 1、安装 安装速度快 pip install mplfinance -i https://pypi.tuna.tsinghua.edu.cn/simple C:\Users>pip install mplfinance -i https://pypi.tuna.tsinghua.edu.cn/simple Defaulting to user installation because normal site-packages is not …