多路复用之select、poll、epoll介绍

一、select

1.1 函数介绍

int select(int max_fd,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);
①第一个参数:为所等待的文件描述符的最大值再+1;
②第二个参数:为所要等待的可读文件描述符集;
③第三个参数:为所要等待的可写文件描述符集;
④第四个参数:为所要等待的异常文件描述符集;
⑤第五个参数:为一个表示时间的结构体,用来设置select的等待时间;

1.2 原理

客户端操作服务器时就会产生这三种文件描述符(简称fd):writefds(写)、readfds(读)、exceptfds(异常),select会阻塞住监视这三类文件描述符,等有数据可读、可写、出异常或超时就会返回;返回后通过遍历fdset整个数组来找到就绪的描述符fd,然后进行对应的IO操作。

1.3 优点

①几乎在所有的平台上支持,跨平台支持性好;

1.4 缺点

①文件描述符有限,默认最大为1024个;
②每次调用select时,均需将fd集合从用户态拷贝至内核态,再次进行遍历;
③对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低,随着文件描述符数量增多而性能下降。

二、poll

2.1 函数介绍

int poll(struct pollfd *fds,nfds_t nfds,int timeout);
①第一个参数:指向一个结构体数组的第0个元素的指针,每个数组元素都是一个struct pollfd结构,用于指定测试某个给定的fd的条件;
②第二个参数:用来指定第一个参数数组元素个数;
③第三个参数:指定等待的毫秒数,无论I/O是否准备好,poll()都会返回;

2.2 优点

①没有最大文件描述符限制,采用链表方式存储fd;

2.3 缺点

①采用轮询方式全盘扫描,随着文件描述符数量增多而性能下降;
②每次调用select时,均需将fd集合从用户态拷贝至内核态,再次进行遍历。

三、epoll

3.1 函数介绍

(1)创建epoll实例:int epoll_create(int size);
①第一个参数:指定了想要epoll实例来检查的文件描述符个数,该参数不是上限值;
(2)修改实例:
int epoll_ctl(int epfd,int op,int fd,struct epoll_event *ev);
①第一个参数:为epoll_create()的返回值;
②第二个参数:用来指定需要执行的操作(添加、修改、删除);
③第三个参数:指明了要修改兴趣列表中的哪一个文件描述符的设定;
④第四个参数:指向结构体epoll_event的指针;
(3)事件等待:
int epoll_wait(int epfd,struct epoll_event *evlist,int maxevents,int timeout);
①第一个参数:是epoll_create()的返回值;
②第二个参数:所指向的结构体数组中返回的是有关就绪文件描述符的信息,数组evlist的空间由调用者负责申请;
③第三个参数:指定所evlist数组里包含的元素个数;
④第四个参数:用来确定epoll_wait()的阻塞行为(三种阻塞行为);

3.2 原理

当文件描述符的内核缓冲区非空的时候,发出可读信号进行通知,当写缓冲区不满的时候,发出可写信号通知的机制。

3.3 优点

①没有最大文件描述符限制,上限为操作系统的最大文件句柄数(1G内存大概支持10万个句柄);
②fd从用户态拷贝至内核态只需一次,使用时间通知机制来触发;
③效率提高且不受文件描述符数量影响,回调通知替换了轮询方式;
④工作模式为水平触发和边缘触发,边缘触发效率比水平触发高,系统不会充斥大量不关心的就绪文件描述符;
⑤分开进行以下操作:“添加/维护待检测任务”、“阻塞线程/进程”;
⑥epoll是基于红黑树来管理待检测集合的;
⑦在epoll中内核和用户之间使用的是共享内存,利用mmap()文件映射内存加速与内核空间的消息传递,减少开销;

3.4 缺点

①只能工作在Linux下。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/xll102500/article/details/129252543