IO多路转接------epoll

epoll是Linux系统中的一种高效IO多路转接机制,相较于select和poll,它在性能上有显著优势。epoll通过epoll_create、epoll_ctl和epoll_wait三个系统调用来实现IO事件的注册、管理和等待。epoll模型利用红黑树存储文件描述符和事件,使用回调机制在事件就绪时通知操作系统,并创建就绪队列以提高效率。epoll支持水平触发和边缘触发两种工作模式,边缘触发具有更高的性能,但需要配合非阻塞IO使用。epoll适用于高并发连接,特别是当连接数大且部分连接活跃时,但对连接数较少的情况效率较低。

        epoll是实现IO多路转接的另一种方式。它与select,poll的作用相同,都是一次等待多个文件描述符。但是,它在接口的使用及原理上与前两者有很大的不同。它改进了select和poll的缺点,使IO操作效率更高。因此它被公认为LInux2.6下性能最好的IO多路转接就绪通知方法。

        下面具体介绍epoll的相关概念。

epoll

        与select,poll不同的是,epoll在使用上有三个相关的系统调用。

1. epoll_create

        函数原型

#include <sys/epoll.h>
int epoll_create(int size);

        该函数的功能是创建一个epoll模型,然后返回一个epoll句柄(相当于文件描述符)。

        参数size的作用是告诉内核关心的文件描述符数目有多大。但是从Liunx2.6.8之后,size参数是被忽略的。所以,这里不进行讨论。

        该函数在调用时,会创建一个struct eventpoll结构体。在该结构体中有两个成员比较重要:


        除了创建上述结构体,还会创建一个回调机制。回调机制的作用是当内核中有数据来时(满足就绪条件时),通知操作系统,这样,操作系统就不用再遍历等待满足就绪条件的文件描述符。

        总结一下,在该函数内部实现以下功能(这些结构如何使用,后续进行说明):

(1)建立回调映射机制

(2)创建一棵空的红黑树;

(3)创建一个空的就绪队列;

2. 注册函数epoll_ctl

        函数原型

#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

        参数说明:

epfd:上述epoll模型的句柄

op:表示采取的操作,该变量的取值有如下几种:

        EPOLL_CTL_ADD:将fd注册到epoll模型中

        EPOLL_CTL_MOD:修改已经注册到epoll模型的的事件类型

        EPOLL_CTL_DEL:删除已经注册到epoll模型中的fd。

fd:对哪个文件描述符进行上述操作

event:表示监听的文件描述符fd上的相关事件信息。该结构体定义如下:

struct epoll_event {
               __uint32_t   events;      /* Epoll events */
               epoll_data_t data;        /* User data variable */
           };

        第一个成员变量表示事件类型,该变量与poll中的events和revents的含义类似。取值都是一个宏,不同的宏表示不同的事件类型,常见的宏为:EPOLLIN(读事件),EPOLLOUT(写事件),EPOLLET(将EPOLL设置为边缘触发,具体使用后面再详细说明)。

        第二个成员变量为一枚举类型变量,结构定义如下:

typedef union epoll_data {
               void        *ptr;
               int          fd;
               __uint32_t   u32;
               __uint64_t   u64;
           } epoll_data_t;

        因为是枚举类型,所以每次在使用时都只能取其中的一个成员变量。fd表示关心的文件描述符,用于存放一个int类型的数据。后两个变量分别用于存放32和64位的数据,具体存放什么数据在实际使用的时候在具体讨论。ptr为一指针,可以接受任意类型的数据,如果关心的文件描述符上的事件除了需要存放fd外,还需要存放其他的变量,此时就可以使用该变量(具体使用后面说明)。

        该函数用于注

### epoll原理 epoll 是 Linux 提供的一种高效的 I/O 多路复用机制,特别适合处理大量并发连接。与传统的 select 和 poll 不同,epoll 将添加/维护待检测任务和阻塞进程/线程两个步骤分开,从而提高了效率。具体来说,epoll 使用 `epoll_ctl()` 来维护等待队列,并使用 `epoll_wait()` 来阻塞进程 [^3]。 epoll 的设计思路是通过红黑树来管理文件描述符,并通过事件驱动的方式通知应用程序哪些文件描述符已经准备好进行 I/O 操作。这种机制避免了每次调用时都需要传递整个文件描述符集合,从而显著减少了系统调用的开销。 ### epoll 的使用方法 要使用 epoll,首先需要创建一个 epoll 文件描述符,然后通过 `epoll_ctl()` 向 epoll 实例中添加或删除感兴趣的文件描述符。最后,通过 `epoll_wait()` 等待 I/O 事件的发生。 以下是一个简单的示例代码,展示了如何使用 epoll 监听管道读取数据: ```c #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/epoll.h> int main(int argc, const char* argv[]) { int fd[2]; pipe(fd); pid_t pid; pid = fork(); if (0 == pid) { // 子进程 close(fd[0]); char buf[5]; char ch = 'a'; while (1) { memset(buf, ch++, 5); write(fd[1], buf, 5); sleep(3); } } else { // 父进程 close(fd[1]); // 创建红黑树 int epfd = epoll_create(1); // 上树 struct epoll_event ev; ev.data.fd = fd[0]; ev.events = EPOLLIN; epoll_ctl(epfd, EPOLL_CTL_ADD, fd[0], &ev); // 监听 struct epoll_event evs[1]; // 接收从内核返回的有变化的文件描述符的数组。 while (1) { int n = epoll_wait(epfd, evs, 1, -1); if (1 == n) { char buf[64] = ""; n = read(fd[0], buf, 64); if (n <= 0) { printf("子进程关闭了写端"); close(fd[0]); epoll_ctl(epfd, EPOLL_CTL_DEL, fd[0], &ev); // 下树 break; } else { printf("读到子进程写的内容:%s\n", buf); } } } } return 0; } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值