网络 I/O复用模型:select、poll、epoll
常见多路复用模型
1.1 常见的多路复用有哪些?
目前主流的多路复用模型主要包含三个,select、poll、epoll
1.1.1 select/poll的工作模式基本一致,底层的系统调用也是一致的,两者最大的区别就是select模型有1024的最大限制,而poll没有1024的限制(但是有最大文件描述符的限制)
select/poll的基本工作流程如下
a、内核拷贝用户态设置好的fd信息至内核内存中
b、在内核态循环检测这些fd(这里是用户设置的全部的fd),检查是否有已经准备好的fd,并将准备的的fd进行置位操作(用于在用户态遍历的时候进行分辨)
c、内核将全部的fd回写到用户态内存中(这里回写的是全部的fd,而不是有事件准备好的fd,这里与epoll有差别,请注意)
1.1.2 epoll的主要函数有:epoll_create、epoll_ctl、epoll_wait
epoll的整个工作流程如下:
a、epoll_create函数(直接在内核中创建一个红黑树的root节点
b、epoll_ctl函数(直接进行系统调用,处理增删改内核中的红黑树)
c、epoll_wait函数(进行系统调用,等待就绪事件的到来)
在日常编程中,我们调用最频繁的函数就是epoll_wait函数,由于我们调用epoll_create、epoll_ctl都是系统调用,直接操作的是内核空间的内存,所以避免了大量的用户空间到内核空间的拷贝工作epoll在内核中的基本结构:
1、红黑树:主要存储着用户需要监听的全部fd信息,另外还有相应事件的回调函数信息等(epoll的所有操作都是系统调用,直接在内核空间中进行操作,且红黑树保存着全部需要监听事件fd的信息)
2、就绪队列:存储着已经就绪的fd的列表(包括读就绪、写就绪、出错等)
1.1.3 epoll监听事件的主要过程如下:
1、监听全部的fd,当有事件到来之后,会在红黑树中查找相应的fd信息,并调用其回调函数,将相应的fd及事件触发的类型进行置位,将fd放入到就绪列表中
2、当我们调用epoll_wait函数时,如果就绪列表不为空,则返回就绪列表中的信息(从内核态拷贝至用户态)如果就绪列表中无x相应的事件:
a、如果设置超时,那么epoll_wait就等待到设置的超时时间,如果还无事件发生,则直接返回(超时的错误),如果有事件到来,则返回相应的事件
b、如果没有设置超时,那么epoll_wait就直接死等,直到有相应的事件到来为止。
整个epoll的过程
1.2简单对比epoll与select/poll的优势
1、检测设置:epoll的所有操作都是操作的内核空间的内存,避免了select/poll的所有操作都是在用户空间中操作,如果要检测相应的fd事件,需要进行一次用户空间到内核空间的拷贝
2、事件检测:select/poll都是检测全部的fd,通过循环遍历的方式来探测相应fd是否有事件到来epoll是则是有事件过来之后,通过查找到相应的fd,进行回调的方式,将相应的fd写入到就绪列表中
3、事件写回:select/poll是将全部的fd都写回至用户态,假设所检测的fd有1000个fd,只有1个fd有事件到来,这种也会将全部的1000个fd返回至用户态epoll与select/poll的最大差别就是epoll只是返回就绪的fd返回至用户态,减少了太多不必要的数据拷贝,从而极大的提升了系统的性能。
资料:
https://www.zhihu.com/question/21092291/answer/3110372649?utm_id=0
https://github.com/Huoke/BookNote/wiki/epoll原理详解.md