158 Linux C++ 通讯架构实战13,epoll 原理和函数介绍,epoll_create,epoll_ctl ,epoll_wait

本文介绍了epoll,一种高性能的I/O多路复用技术,尤其在高并发场景下表现出色。主要讲解了epoll_create、epoll_ctl和epoll_wait函数的作用和原理,以及它们如何通过红黑树和双向链表实现事件管理。
摘要由CSDN通过智能技术生成

epoll技术简介


    //(2.1)epoll概述
    //(1)I/O多路复用:epoll就是一种典型的I/O多路复用技术:epoll技术的最大特点是支持高并发;
    //传统多路复用技术select,poll,在并发量达到1000-2000,性能就会明显下降;
    //epoll,kquene(freebsd)
    //epoll,从linux内核2.6引入的,2.6之前是没有的;
    //(2)epoll和kquene技术类似:单独一台计算机支撑少则数万,多则数十上百万并发连接的核心技术;
    //epoll技术完全没有这种性能会随着并发量提高而出现明显下降的问题。但是并发没增加一个,必定要消耗一定的内存去保存这个连接相关的数据;
     //并发量总还是有限制的,不可能是无限的;
    //(3)10万个连接同一时刻,可能只有几十上百个客户端给你发送数据,epoll只处理这几十上百个客户端;
    //(4)很多服务器程序用多进程,每一个进程对应一个连接;也有用多线程做的,每一个线程对应 一个连接;
    //epoll事件驱动机制,在单独的进程或者单独的线程里运行,收集/处理事件;没有进程/线程之间切换的消耗,高效
    //(5)适合高并发,融合epoll技术到项目中,作为大家将来从事服务器开发工作的立身之本;
    //写小demo非常简单,难度只有1-10,但是要把epoll技术融合到商业的环境中,那么难度就会骤然增加10倍;

学习epoll要达到的效果及一些说明


    //(1)理解epoll的工作原理;面试考epoll技术的工作原理;
    //(2)开始写代码
    //(3)认可nginx epoll部分源码;并且能复用的尽量复用;

三:epoll原理与函数介绍:三个函数,理解好就等于掌握了epoll技术的工作原理,以下内容务必认真理解。

掌握这个三个函数的使用,并结合网上一些大神关于如何自己实现这个三个函数的源码分析,epoll的三个关键函数都干了什么。

大神源码:

    //https://github.com/wangbojing
    //a)c1000k_test这里,测试百万并发的一些测试程序;一般以main();
    //b)ntytcp:nty_epoll_inner.h,nty_epoll_rb.c
    //epoll_create();
    //epoll_ctl();
    //epoll_wait();
    //epoll_event_callback();
    //c)总结:建议学习完老师的epoll实战代码之后,再来学习 这里提到的课件代码,事半功倍;

epoll_create()函数

原型  : int epoll_create(int size);

功能:创建一个epoll对象,

        返回该对象的描述符【文件描述符】,这个描述符就代表这个epoll对象,后续会用到;
    //这个epoll对象最终要用close(),因为文件描述符/句柄 总是关闭的;

参数:size表示你要连接的客户端数量

这个值是建议内核的,假设我们写了100,但是当您的连接数量超过100的时候,内核会给你自动分配

size: >0;

从大神的代码中分析epoll的原理可知:

epoll_create是创建了一个红黑树的节点,

    //原理:这个当前看不懂源码也没有关系,先知道大概咋回事,要看懂这块,必须数据结构很明白。
    //a)struct eventpoll *ep = (struct eventpoll*)calloc(1, sizeof(struct eventpoll)); 
    //b)rbr结构成员:代表一颗红黑树的根节点[刚开始指向空],把rbr理解成红黑树的根节点的指针;
    //红黑树,用来保存  键【数字】/值【结构】,能够快速的通过你给key,把整个的键/值取出来;
    //c)rdlist结构成员:代表 一个双向链表的表头指针;
    //双向链表:从头访问/遍历每个元素特别快;next。
    //d)总结:创建了一个eventpoll结构对象,被系统保存起来;
       //rbr成员被初始化成指向一颗红黑树的根【有了一个红黑树】;
       //rdlist成员被初始化成指向一个双向链表的根【有了双向链表】;

epoll_ctl 控制某个epoll监控的文件描述符上的事件:注册、修改、删除。也就是说,有了这个红黑树了,就要给树上挂节点了,或者删除节点,或者修改节点了

红黑树上的每一个节点的内容都是如下的一个struct epitem。

每次使用 epoll_ctl实际上就是 将一个struct epitem  从根节点的红黑树上 添加/删除/修改、

 

原型

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

参数

因此第一个参数是 这个红黑树的根节点,就是告诉系统,我要对这个红黑树进行改动。

第二个参数是说明,我是挂节点/删除节点/修改节点的哪一种

第三个参数是说明,我要挂的节点的 fd,或者删除节点的fd,或者修改节点的fd

第四个参数说明:

我对第三个参数的什么事件进行监控:events表明了是对读:EPOLLIN,写:EPOLLOUT,错误EPOLLERR,  边缘触发模式:EPOLLET

然后做为传入参数,描述了我要做什么事情,里面还有一个fd,对应了epoll_ctl的第三个参数。学到这里的时候有一个想法,就是为什么在还需要第四个参数中有一个fd,且这个fd和第三个参数是一样的,网上也没有找到合理的说明,那么只有一种可能,就是epoll_event 做为参数使用的时候,要用到fd,但是epoll的开发者又不想依赖于外部条件,因此将这个参数再填写一遍

void *ptr //这个todo

#include <sys/epoll.h>

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

epfd: 为epoll_creat的句柄

op: 表示动作,用3个宏来表示:

        EPOLL_CTL_ADD (注册新的fd到epfd),

        EPOLL_CTL_MOD (修改已经注册的fd的监听事件),

        EPOLL_CTL_DEL (从epfd删除一个fd);

event: 告诉内核需要监听的事件

struct epoll_event {

        __uint32_t events; /* Epoll events */

        epoll_data_t data; /* User data variable */

};

typedef union epoll_data {

        void *ptr;

        int fd;  //  和 epoll_ctl的第三个参数一样

        uint32_t u32;  //不用

        uint64_t u64; //不用

} epoll_data_t;

events 取值为:

        EPOLLIN : 表示对应的文件描述符可以读(包括对端SOCKET正常关闭)

        EPOLLOUT: 表示对应的文件描述符可以写

        EPOLLPRI: 表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来)

        EPOLLERR: 表示对应的文件描述符发生错误

        EPOLLHUP: 表示对应的文件描述符被挂断;

        EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)而言的

        EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里

参考大神实现epoll_ctl代码:

	//原理:
	//a)epi = (struct epitem*)calloc(1, sizeof(struct epitem));
	//b)epi = RB_INSERT(_epoll_rb_socket, &ep->rbr, epi); 【EPOLL_CTL_ADD】增加节点到红黑树中
	  //epitem.rbn ,代表三个指针,分别指向红黑树的左子树,右子树,父亲;
	  //epi = RB_REMOVE(_epoll_rb_socket, &ep->rbr, epi);【EPOLL_CTL_DEL】,从红黑树中把节点干掉
	  //EPOLL_CTL_MOD,找到红黑树节点,修改这个节点中的内容;

	//红黑树的节点是epoll_ctl[EPOLL_CTL_ADD]往里增加的节点;面试可能考
	//红黑树的节点是epoll_ctl[EPOLL_CTL_DEL]删除的;
	//总结:
	//EPOLL_CTL_ADD:等价于往红黑树中增加节点
	//EPOLL_CTL_DEL:等价于从红黑树中删除节点
	//EPOLL_CTL_MOD:等价于修改已有的红黑树的节点

返回值:

成功:0;失败:-1,设置相应的errno

epoll_wait 等待所监控文件描述符上有事件的产生,类似于select()调用。

函数原型

#include <sys/epoll.h>

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)

参数

events: 用来存内核得到事件的集合,可简单看作数组。是传出参数,传出满足监听条件的那个fd结构体

maxevents: 告之内核这个events有多大,也就是说,这次epoll_wait 可以收集到的events的个数,这个maxevents的值不能大于创建epoll_create()时的size,

timeout: 是超时时间

-1: 阻塞

0: 立即返回,非阻塞

>0: 指定毫秒

返回值:

成功返回有多少文件描述符就绪,时间到时返回0,出错返回-1

     //说白了就是遍历这个双向链表,把这个双向链表里边的节点数据拷贝出去,拷贝完毕的就从双向链表里移除;
    //因为双向链表里记录的是所有有数据/有事件的socket【TCP连接】;
    //参数epfd:是epoll_create()返回的epoll对象描述符;
    //参数events:是内存,也是数组,长度 是maxevents,表示此次epoll_wait调用可以收集到的maxevents个已经就绪【已经准备好的】的读写事件;
      //说白了,就是返回的是 实际 发生事件的tcp连接数目;
    //参数timeout:阻塞等待的时长;

epitem结构设计的高明之处:既能够作为红黑树中的节点,又能够作为双向链表中的节点;

  • 15
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这三个函数都是与 Linux 系统中的 epoll I/O 多路复用机制相关的函数。 1. `epoll_create` 函数用于创建一个 epoll 文件描述符,返回值即为该文件描述符。该函数的原型为: ```c int epoll_create(int size); ``` 其中参数 `size` 表示 epoll 实例中能够关注的最大文件描述符数目,一般可以设置为任意大于 0 的数。 2. `epoll_ctl` 函数用于控制 epoll 实例中的文件描述符,可以用于添加、修改和删除文件描述符的关注事件。该函数的原型为: ```c int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); ``` 其中 `epfd` 参数表示 epoll 文件描述符,`op` 参数表示操作类型,可选的取值有 `EPOLL_CTL_ADD`、`EPOLL_CTL_MOD` 和 `EPOLL_CTL_DEL`,分别表示添加、修改和删除操作。`fd` 参数表示需要被添加、修改或删除的文件描述符,`event` 参数表示需要关注的事件,包括事件类型和事件数据等信息。 3. `epoll_wait` 函数用于等待 epoll 实例中的文件描述符上发生关注的事件,该函数会阻塞进程直到有事件发生。该函数的原型为: ```c int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); ``` 其中 `epfd` 参数表示 epoll 文件描述符,`events` 参数表示事件数组,用于存储返回的事件信息,`maxevents` 参数表示最大返回的事件数目,`timeout` 参数表示超时时间,单位为毫秒,如果设置为 -1 则表示永久阻塞直到有事件发生。 总的来说,epoll I/O 多路复用机制通过 `epoll_create` 函数创建一个 epoll 实例,并通过 `epoll_ctl` 函数控制实例中的文件描述符。然后通过 `epoll_wait` 函数等待文件描述符上发生关注的事件,从而实现高效的 I/O 多路复用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值