Linux——IO模型_多路转接(epoll)

目录

 0.往期文章

1.epoll的三个接口

1.epoll_create

2.epoll_ctl

结构体 epoll_event

3.epoll_wait

2. epoll的工作原理,和接口对应

1.理解数据到达主机

2.epoll的工作原理

 3.基于epoll的TCP服务器(代码)

 辅助库

基于TCP的Socket封装

服务器代码

测试

 4.epoll的工作模式

边缘触发(Edge Triggered, ET)模式

水平触发(Level Triggered, LT)模式

理解 ET 模式和非阻塞文件描述符


 0.往期文章

Linux--应用层协议HTTP协议(http服务器构建)-优快云博客

Linux--传输层协议UDP-优快云博客

Linux--传输层协议TCP-优快云博客

1.epoll的三个接口

定位:只负责进行等,不进行拷贝。
作用:epoll系统调用是用来让我们的程序监视多个文件描述符的状态变化的;程序会停在epoll这里等待, 直到被监视的文件描述符有一个或多个发生了状态改变。

1.epoll_create

  • 参数
    • size:这是内核用来内部优化 epoll 实例的提示值,表示你预期将要添加到 epoll 实例中的文件描述符的最大数量。然而,这个参数在 Linux 2.6.8 及以后的版本中实际上被忽略了,因为内核能够动态地调整大小。
  • 返回值
    • 成功时,返回一个非负整数,即新创建的 epoll 实例的文件描述符。
    • 出错时,返回 -1,并设置 errno 以指示错误原因。

2.epoll_ctl

参数:

  • epfd:这是由 epoll_create 或 epoll_create1 返回的 epoll 实例的文件描述符。它指定了要操作的 epoll 实例。
  • op:这是一个操作码,指定了要对目标文件描述符 fd 执行的操作类型。有效的操作码包括:
    • EPOLL_CTL_ADD:向 epoll 实例注册一个新的文件描述符,以便监视其上的事件。
    • EPOLL_CTL_MOD:修改已经注册到 epoll 实例中的文件描述符的事件类型或用户数据。
    • EPOLL_CTL_DEL:从 epoll 实例中删除一个文件描述符,停止对其上事件的监视。
  • fd:这是要操作的目标文件描述符,即要注册、修改或删除的文件描述符。
  • event:这是一个指向 struct epoll_event 结构体的指针,它包含了要注册或修改的事件信息。如果操作是 EPOLL_CTL_DEL,则此参数可以为 NULL。

返回值:

  • 成功时,epoll_ctl 返回 0。
  • 出错时,返回 -1,并设置 errno 以指示错误原因。
结构体 epoll_event
typedef union epoll_data {  
    void    *ptr;  
    int      fd;  
    uint32_t u32;  
    uint64_t u64;  
} epoll_data_t;  
  
struct epoll_event {  
    uint32_t    events;   /* Epoll 事件类型 */  
    epoll_data_t data;    /* 用户数据 */  
};
  • events:这是一个位掩码,用于指定要监视的事件类型。常见的事件类型包括 EPOLLIN(可读事件)、EPOLLOUT(可写事件)、EPOLLERR(错误事件)等。此外,epoll 还支持 EPOLLET(边缘触发模式)和 EPOLLONESHOT(只触发一次,就移除该fd)等特殊事件类型。
  • data:这是一个联合体,包含了用户数据。它可以是一个指针、文件描述符、32位或64位无符号整数。这个数据在事件触发时会原样返回给用户,以便用户识别是哪个文件描述符触发了事件。

3.epoll_wait

参数:

  • epfd:这是由 epoll_create 或 epoll_create1 返回的 epoll 实例的文件描述符。它指定了要等待事件的 epoll 实例。
  • events:这是一个指向 struct epoll_event 结构体数组的指针,用于接收准备就绪的事件。在调用 epoll_wait 后,该数组会被填充为准备就绪的文件描述符和它们关联的事件(如读就绪、写就绪等)。
  • maxevents:这个参数指定了 events 数组可以容纳的最大事件数。epoll_wait 最多会返回这个数目的准备就绪事件。如果少于这个数目的事件准备就绪,那么实际返回的事件数会少于 maxevents
  • timeout:这个参数指定了 epoll_wait 在没有事件准备就绪时应等待的最长时间(以毫秒为单位)。如果设置为 -1,epoll_wait 将无限期地等待,直到至少有一个事件准备就绪。如果设置为 0,epoll_wait 将立即返回,不等待任何事件发生。如果设置为一个正整数 N,epoll_wait 将等待最多 N 毫秒。

返回值:

  • 当成功时,epoll_wait 返回准备就绪的文件描述符数量。如果返回值为 0,表示在指定的超时时间内没有事件发生。
  • 当出错时,返回 -1,并设置全局变量 errno 以指示错误类型。

注意事项:

  • epoll_wait 是阻塞调用,这意味着在指定的超时时间内如果没有任何事件准备就绪,调用线程将被阻塞。如果超时时间到达并且没有事件准备就绪,epoll_wait 将返回 0。
  • epoll_wait 使用的 epoll_event 结构体包含了与事件相关的文件描述符和数据。在调用 epoll_wait 后,用户可以通过遍历 events 数组来处理所有准备就绪的事件。
  • epoll_wait 是 Linux 下进行高性能网络编程和并发编程的重要工具之一,它能够显著提高处理大量并发连接时的效率和可扩展性。

2. epoll的工作原理,和接口对应

1.理解数据到达主机

        数据到达主机的过程是一个复杂的多层封装与解封装过程,涉及到了网络协议栈的各个层次以及网络设备的协同工作。这个过程确保了数据能够准确、可靠地从源主机传输到目的主机。

        但是数据到主机,一定先经过网卡的,由网卡将数据交给网络协议栈,OS又如何知道网卡中有数据呢?

        答案是,中断机制

        当网卡接收到数据时,它会通过中断的方式通知CPU。中断是CPU与硬件设备之间的一种通信方式,用于在硬件事件发生时请求CPU的注意。当网卡接收到一个数据包时,它会触发一个中断信号,该信号被发送到CPU的中断控制器。CPU在接收到中断信号后,会暂停当前正在执行的程序,转而执行一个中断服务例程(ISR),该例程负责处理网卡接收到的数据。

2.epoll的工作原理

        当OS创建epoll模型,首先要在底层构建一颗红黑树。每个红黑树的结点一定要包括以下几个字段:int fd; unit32_t events; struct rb_node*left ,*right。

        该红黑树用来标识用户让内核关心的fd及其对应的事件。该红黑树由epoll_ctl进行增加,删除,修改操作。 fd就是key值。除了维护红黑树,还要维护一个就绪队列,其中每个结点包括:int fd; unit32_t revents; struct node*next ,*prev。

        一旦网卡中有数据了,网卡同个中断交给OS,接着网络协议栈就拿到数据了,所以在输入和输出缓冲区里有没有数据,OS是很清楚的,OS在缓冲区中设置回调方法,该回调方法就是epoll_ctl构建的。底层一旦有数据就绪并且是用户关心的,此时OS就会调用回调方法构建就绪队列的结点,填充清楚,是哪一个fd的什么事件已经就绪了,并连入就绪队列。

        上层要知道哪些数据就绪了,就可以直接调用epoll_wait,他会将相关的结点通过events字段返回出去。所以epoll检测有没有就绪事件, 这个过程的事件复杂度就是O(1),因为epoll_wait只需要检测就绪队列是否为空。获取就绪事件只能是O(N),因为只能将结点一个一个拷贝到events字段,在这个过程中,epoll_wait会将就绪事件,依次言给按照顺序放入到我们定义的用户缓冲区数组中。

        那么使用epoll_create就能创建一个epoll模型,只要有需要,在OS中是可以同时存在多个epoll模型的,那么OS就要管理存在的epoll模型:

        当某一进程调用 epoll_create 方法时, Linux 内核会创建一个 eventpoll 结构体, 这个结构体中有两个成员(红黑树和就绪队列)与 epoll 的使用方式密切相关.

  • 每一个 epoll 对象都有一个独立的 eventpoll 结构体, 用于存放通过 epoll_ctl 方法向 epoll 对象中添加进来的事件.
  • 这些事件都会挂载在红黑树中, 如此, 重复添加的事件就可以通过红黑树而高效的识别出来(红黑树的插入时间效率是 lgn, 其中 n 为树的高度).
  • 而所有添加到 epoll 中的事件都会与设备(网卡)驱动程序建立回调关系, 也就是说, 当
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值