《Linux高性能服务器编程》学习笔记(九)--I/O复用

学习更多,请点击:《Linux高性能服务器编程》学习笔记:目录索引


select函数

函数参数详解

#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
1.形参(后四个参数均是输入输出型参数):
nfds:被监听的文件描述符的总数,值一般设为所以文件描述符中最大的值+1
readfds:位图,每个值为1的位代表用户想让操作系统监听是否具有读事件发生的文件描述符
writefds:位图,每个值为1的位代表用户想让操作系统监听是否具有写事件发生的文件描述符
exceptfds:位图,每个值为1的位代表用户想让操作系统监听是否具有异常事件发生的文件描述符
timeout:超时时间,代表select函数将要等待的时间,也是一个输入输出型参数
2.返回值:已有事件发生的文件描述符的个数,从位图上看就是fd_set结构体中已经被内核置1的位数

函数用到的两个结构体fd_set和fd_array(图解)

这里写图片描述

对fd_set类型结构体操作的函数

void FD_CLR(int fd, fd_set *set);将set中fd对应的位,置0
int FD_ISSET(int fd, fd_set *set);判断set中fd对应的位是否存在(即是否为1)
void FD_SET(int fd, fd_set *set);将set中fd对应的位,置1
void FD_ZERO(fd_set *set);将set中所有的位,置0

poll函数

函数参数详解

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
1.形参(①和③是输入输出型参数):
fds:数组,存储pollfd类型结构体
nfds:数组大小
timeout:超时时间,同select函数的timeout一样
2.返回值:同select一样

函数用到的两个结构体pollfd和fds(图解)

这里写图片描述

pollfd类型结构体中events和revents的取值

POLLIN:数据(包括普通数据和优先数据)可读,可作为输入,可作为输出
POLLOUT:数据可写(包括普通数据和优先数据),可作为输入,可作为输出
POLLERR:错误,不可作为输入,可作为输出
还有其他的,在这不一一列举了

epoll函数

epoll函数三部曲形参详解

#include <sys/epoll.h>
1.int epoll_create(int size);
1.形参:
size:表示想让内核知道创建一个事件表需要多大的空间
2.返回值:成功返回创建的事件表的文件描述符,失败返回-1
2.int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
1.形参:
epfd:epoll_create的返回值,事件表文件描述符
op:要执行的操作,包括下面三个选项:
EPOLL_CTL_ADD 给fd文件描述符添加event事件
EPOLL_CTL_MOD 将fd文件描述符上的事件修改成event事件
EPOLL_CTL_DEL 删除fd文件描述符上的事件,event参数写NULL
fd:想要操作事件的文件描述符
event:该结构体包括两个成员:
events 取值和poll函数中pollfd结构体中的events的取值一样,只不过是在前面加上’E’
data 该联合体有四个成员,最常用到int fd成员,存储事件所属的文件描述符fd
2.返回值:成功返回0,失败返回-1
3.int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
1.形参:
epfd:epoll_create的返回值,事件表文件描述符
events:用于存储事件表中所有已发生的事件,即输出型参数,它使得epoll大大提高了效率
maxevents:最多监听事件数量
timeout:同poll和select的timeout参数
2.返回值:同select一样

epoll三部曲函数用到的结构体和事件表(图解)

这里写图片描述
这里写图片描述

select、poll、epoll函数的优缺点

select

优点:
相比较之前的一些IO函数,select函数是让操作系统监视多个文件描述符的状态变化;程序会阻塞在select函数这里,直到被监视的文件描述符有一个或多个发生了状态改变;用钓鱼来举例就是:以前我们是一人一根鱼竿,现在是一人多根鱼竿;以前只能干等一个,现在是只要多根鱼竿中任一个或多个有鱼上钩就可以收竿,这就大大提升了我们钓到鱼(获取到数据)的概率。
缺点:
★因为使用fd_set位图结构体对应文件描述符,所以能存储的文件描述符有上限,一般是1024
★每次调用select,都需要把存放文件描述符的集合从用户态拷贝到内核态,开销很大
★在内核态中,也需要对文件描述符集合进行遍历查找,因为是线性结构,所以时间复杂度是O(n),随着文件描述符的增加,效率就会变低
④select函数这个接口需要传的参数很多,并且都要先手动设置好后再传入,而且其中的输入输出型参数并未实现输入输出分离,因为还需要用户自己定义一块缓冲区存储原先的数据,从用户使用角度来说不太方便

poll

优点:
在select的基础上,改进了select的两个缺点:
取消了能存储的文件描述符上限,因为使用了数组
实现了输入输出参数的分离,因为使用了events存储“用户注册的事件(用户手动设置)”,使用revents存储“已经发生了的事件(内核填充)”
缺点:
同select函数的其他缺点一样

epoll

优点:
文件描述符数目无上限,底层使用红黑树存储,来一个插一个!
红黑树保证了查找的效率,时间复杂度为O(log n)
③因为回调函数机制使得就绪队列里存储的都是已经就绪(即发生了事件)的文件描述符,所以这保证了epoll_wait函数返回时带出的events数组中全部都是已经就绪的文件描述符。这非常适用于“链接多,活跃少”的场景,比如QQ,游戏的创房机制等场景。
缺点:
几乎没有缺点,就我个人而言,像我这样的小菜鸡,我就觉得epoll唯一的缺点就是初学时比较难懂

猜你喜欢

转载自blog.csdn.net/w_y_x_y/article/details/81171919