linux io 复用基础 select epoll函数实现过程

select 是一种异步实现技术,poll与epoll都是给予select 来实现的,因此学会select至关重要,它会告诉你哪一个io事件就绪
首先了解 select 函数在 c语言之中的定义:
int select(int n,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout);
函数参数介绍:
1,n 表示文件标识符,int 类型 在Linux无论是文件、设备和管道,甚至是个可操作对象对可以视作文件来对待,具体表现为都可以用这个文件标识符来操作他们
2,readfds 是 io 读事件存储集合,里面存储的是所有读io操作事件
3,writefds 是 io 写事件的集合,
4,exceptfds 是 io 错误事件集合
5,timeout 表示 在这个时间段之内没有事件的发生就会返回 0
函数返回值介绍:
1,返回的是事件总数,如果读操作有1个,写操作有1个,那么就会返回 2
2,如果返回-1 ,那么表示事件出错
3,如果返回 0 表示在定义的时间段之内没有监听的事件发生
4,一般只会监听一个事件,直接根据select 就可以判断事件是否活跃,如果是监听多个事件需要集合操作函数来判断
集合操作函数:
1,关于集合,里面存储的只是活跃的事件,因此判断io是否有到达,只需要遍历集合就可以。
2,select 函数监视的文件描述符分3类,分别是writefds、readfds、和exceptfds。调用后select函数会阻塞,直到有描述副就绪(有数据 可读、可写、或者有except),或者超时(timeout指定等待时间,如果立即返回设为null即可),函数返回。当select函数返回后,可以 通过遍历fdset,来找到就绪的描述符
   FD_CLR(inr fd,fd_set* set);//用来清除描述词组set中相关fd 的位,取出事件,并在集合之中清除所取出的事件
    FD_ISSET(int fd,fd_set *set);//用来测试描述词组set中相关fd 的位是否为真,判断事件是否活跃
    FD_SET(int fd,fd_set*set);//用来设置描述词组set中相关fd的位,将事件放置集合之中
    FD_ZERO(fd_set *set);//用来清除描述词组set的全部位,也就是集合之余空
缓存区的原理以及实现(内核缓冲区):
1,缓冲区的引入是为了减少频繁I/O操作而引起频繁的系统调用(耗时),当你操作一个流时,更多的是以缓冲区为单位进行操作.
2,首先A往管道写入,这时候内核缓冲区由空的状态变到非空状态,内核就会产生一个事件告诉B该醒来了,这个事件称之为“缓冲区非空”
3,“缓冲区非空”事件通知B后,B却还没有读出数据;且内核许诺了不能把写入管道中的数据丢掉这个时候,A写入的数据会滞留在内核缓冲区中,如果内核也缓冲区满了,B仍未开始读数据,最终内核缓冲区会被填满,这个时候会产生一个I/O事件,告诉进程A,你该等等(阻塞)了,事件定义为“缓冲区满”
4,B终于开始读数据了,于是内核的缓冲区空了出来,这时候内核会告诉A,内核缓冲区有空位了,你可以从长眠中醒来了,继续写数据了,事件叫做“缓冲区非满”
5,事件Y1已经通知了A,但是A也没有数据写入了,而B继续读出数据,知道内核缓冲区空了。这个时候内核就告诉B,你需要阻塞了!事件为“缓冲区空”
6,这四个情形涵盖了四个I/O事件,缓冲区满,缓冲区空,缓冲区非空,缓冲区非满,这四个I/O事件是进行阻塞同步的根本,四个事件是我自己起的名字
linux epool实现过程:
1,epoll 使用一个文件描述符管理多个文件描述符(一个代理可以同时观察许多流的I/O事件),在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞态中醒来
2,epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll之会把哪个流发生了怎样的I/O事件通知我们,实际上存储到了一个事件表之中,这样用户态到内核态只复制了一次.
3,epoll_create 创建一个epoll对象,一般epollfd = epoll_create()
epoll_ctl(epoll_add/epoll_del的合体),往epoll对象中增加/删除某一个流的某一个事件
epoll_ctl(epollfd, EPOLL_CTL_ADD, socket, EPOLLIN);注册缓冲区非空事件,即有数据流入
epoll_ctl(epollfd, EPOLL_CTL_DEL, socket, EPOLLOUT);注册缓冲区非满事件,流可以被写入
epoll_wait(epollfd,...)等待直到注册的事件发生
select与epoll的区别:
1,使用select,我们有O(n)的无差别轮询复杂度,同时处理的流越多,无差别轮询时间就越长.
2,我们对这些流的操作都是有意义的。(复杂度降低到了O(1))
3,在连接并发高的情况之下,连接活跃度低,epoll好于select
4,在连接并发性不高,同时连接很活跃(连接断开次数多),select好于epoll


posted @ 2018-09-16 16:22  十七楼的羊  阅读(170)  评论(0编辑  收藏  举报