epoll模型

前言

最近一段时间看epoll的源码,看的抓耳挠腮。本着分享的原则,分享一下我对epoll的理解,注意:本文并不能让你从零开始学epoll,而是希望在你看epoll源码也学的抓耳挠腮的时候,看到本文能对你有一丢小小的帮助。

epoll的整个流程

本篇文章并不会设计到具体源码,只是涉及到epoll的数据交互的流程。

epoll_create

一个应用程序,想要使用epoll模型,首先会创建一个epoll模型。epoll_create是在内核创建一个epoll模型,你可以把这个模型想象做一个java对象。这个对象里有一个阻塞列表,一个就绪列表,一个红黑树。

epoll_ctl

每一次通讯,客户端都会建立一个socket,socket有一个文件描述符fd,系统通过这个fd去操作socket,系统会封装一个epitem(红黑树的节点),这个epitem包含socket和一个回调事件(当然还有其他属性,我们暂且不提)。然后内核会把这个epitem添加到红黑树,当然,也可以修改和删除事件。

epoll_wait

用户进程去就绪列表拿就绪事件。拿到就返回,拿不到就进入epoll阻塞列表,当然也可以设置超时参数为0表示拿不到也立即返回。

回调事件

回调事件会根据监听的事件类型,把fd放到就绪列表。然后去通知阻塞进程。阻塞进程从就绪列表拿走就绪事件,也就是把就绪事件从内核空间拷贝到用户空间。

这是我对epoll模型的大概描述,接下来,从交互的层面再说一说:

网络的一个数据包,是怎么找到具体的对应的socket的回调事件的。

当一个数据包从网络传输过来,包含了协议,发送端ip 和端口,目标端ip和接口(这也是socket的五大元素)。内核根据这五个要素去找到对应的socket,就可以拿到对应的fd,有了fd,就可以去红黑树里找epitem,找到了epitem就可以去触发回调事件。回调事件就可以把就绪事件放到就绪列表。
输入netstat命名就可以查看系统的所有活跃的socket链接:


image.png

例子里,本地机器有两个socket链接和172.217.27.42.443端口建立了链接,当网络数据包传输过来,发送端ip和端口号就是172.217.27.42.443,接收端可能是54040和54035端口,用发送端ip和端口号为参数去对应foreign address,用接收端参数去对应local address,就可以找到具体的哪一个socket连接。

备用链表

如果在拷贝就绪事件的时候,出现了新的就绪事件怎么办,其实还有一个备用链表,拷贝事件的时候,如果有就绪事件产生,先放到备用链表,拷贝完成再把备用链表的就绪事件放到就绪列表里。

和select/ poll模型比较

epoll模型肯定是比select或者poll模型更复杂了。可以把epoll类比于重型挖掘机,select或者poll就是轻型挖机,各有各的用途,重活面前,epoll肯定好用。但是活少而清的时候,select/poll模型反而更有优势。

如果想看细节,还是得自己撸源码,别人讲只能听个大概。

你可能感兴趣的:(epoll模型)