艾巴生活网

您现在的位置是:主页>科技 >内容

科技

深度解读epoll(的原理)

2024-11-29 23:35:02科技帅气的蚂蚁
Epoll可以说是编写高性能服务器端程序的必备技术。在介绍epoll之前,让让我们看一看多路复用I O。多路复用I O多路复用I O:是指内核负责监控

深度解读epoll(的原理)

Epoll可以说是编写高性能服务器端程序的必备技术。在介绍epoll之前,让让我们看一看多路复用I/O。

多路复用I/O多路复用I/O:是指内核负责监控多个I/O流,当任何一个I/O流处于就绪状态(可读或可写)时,就会通知进程,以便可以处理那个I/O流上的数据。如图1所示:

如图1所示,内核负责监控多个I/O流。当一些I/O流准备好时,内核会将这些I/O流添加到就绪队列中,然后通知进程处理就绪队列中的I/O流。

与传统的阻塞I/O相比,多路复用I/O的优点是可以同时监听多个I/O流,并将准备好的I/O流通知进程。

在介绍完epoll和复用I/O的原理之后,我们再来介绍一下我们的主角:epoll。

在Linux系统中,有许多多路复用I/O的实现,如select和poll。而且epoll也是多路I/O的一种实现,相比select和poll,epoll在性能上有很大的提升。

红色黑色的树

在epoll内部,红黑树用于存储所有被监控的套接字。红黑树是平衡二叉树,添加和搜索元素的时间复杂度为O(log n)。其结构如图2所示:

Epoll使用套接字句柄作为密钥,并将套接字保存在红黑树中。如图2所示,每个节点中的数字代表套接字句柄。

在红黑树中保存被监控套接字的目的是在修改被监控套接字的读写事件时,通过套接字句柄快速找到对应的套接字对象。

就绪队列

此外,epoll还维护一个就绪队列。当epoll监控的套接字状态改变时(变为可读或可写),就绪套接字将被添加到就绪队列中。如图3所示:

当socket从网络中获取数据时,会通知epoll,epoll会将当前socket添加到就绪队列中,并唤醒等待进程(即调用epoll _ WAIT的进程)。

当套接字状态改变时,将调用ep_poll_callback函数来通知epoll。让让我们来看看这个函数的处理过程:

static int EP _ poll _ callback(wait _ queue _ t * wait,unsigned mode,int sync,void *key){ .struct epitem * epi=EP _ item _ from _ wait(wait);struct event poll * EP=epi-》EP;//1)将套接字添加到就绪队列list _ add _ tail (epi-rdlink,EP-》rdllist);

Is _ linked://2)调用epoll_wait()后唤醒被阻塞的进程if(wait queue _ active(EP-WQ))wake _ up _ locked(EP-WQ);返回1;}

ep_poll_callback函数的意图很明确,它主要完成两个任务:

将就绪套接字添加到就绪队列中。

通过调用epoll_wait函数唤醒被阻塞的进程。

当进程被唤醒时,它会将就绪队列中的就绪套接字复制到用户提供的数组中。如图4所示:

如图4所示,在调用epoll_wait时,需要提供一个事件数组来存储ready socket。当epoll_wait返回时,用户可以从事件数组中获取就绪套接字,并可以对其进行读写。

综上所述,本文主要以举例说明的方式介绍epoll的原理,但很多实现细节只有看源代码才能理解。

japan quarterly 日本季刊