I/o多路转接之select:
一、select:
1、特点:负责等
2、可以等待多个fd(read负责读取)
系统提供select函数来实现多路复用输入/输出模型
输入:用户想告诉操作系统哪个是你应该关心的读事件
输出:操作系统告诉用户你所关心的文件描述符上的事件哪些是fd已经就绪
二、select函数原型:
#include<sys/select.h>
int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);
三、理解select执行过程:(理解fd_set)
fd_set长度为1字节,fd_set中的每一bit可以对应一个fd,则1字节长的fd_set最大可以对应8个fd。
用int数组来保存文件描述符
四、socket就绪条件:
1、读就绪
1)、Socket内核中接受缓冲区的字节数>=低水位标记SO_RCVLOWAT,可以无阻塞的读
2)、监听的Socket上有新的链解请求
3)、socket上有未处理的错误
4)、Socket Tcp通信中,对端关闭连接,此时对该Socket读,则返回0;
2、写就绪:
1)、Socket内核中,发送缓冲区的可用字节数》=低水位标记SO_RCVLOWAT,此时可以无阻塞的写
2)、Socket的写操作被关闭(close或者shutdown),对一个写操作被关闭的Socket进行写操作,会触发SIGPIPE信号
3)、Socket使用非阻塞connect连接成功或失败后
4)、Socket上有未读取的错误
3、异常就绪:Socket上收到带外数据。(有一个紧急指针的字段)
五、select的特点:
1)可监控的文件描述符个数取决与sizeof(fdset)的值,例:sizeof(fdset)=512,每bit表示一个文件描述符,则此服务器上最大的文件描述符是512*8=4096.
2)fd加入select监控集,再使用一个数组array保存放到select监控集中的fd
*用于再select返回后,array作为源数据和fdset进行DISSSET判断
*****Select返回后把以前加入的但并无事件发生的fd清空,每次开始select前都必须从array数组取得fd逐一加入,扫描array的同时取得fd最大值maxfid,用于select的第一个参数。
六、selec的缺点:
1)性能降低,代码难写
2)数组承载有上限(位图有大小,所存的文件描述符就有限)
3)开销大
4)输入输出函数混合在一起必须依赖一个第三方数组
I/O多路转接之poll:
一、函数接口:
#include<poll.h>
int poll(struct pollfd *fds,nfds_t nfds,int timeout);
//pollfd 结构
struct pollfd{
int fd; /*file descriptor*/
short events; /*requested events*/
short revents; /*returned events*/
};
2、events和revents的取值
events:所关心的fd是什么
revents:所关心的fd哪些已经就绪
3、返回结果:
1)返回值小于0,表示出错
2)返回值等于0,表示poll函数等待超时;
3)返回值大于0,表示poll由于监听的文件描述符就绪而返回。
二、socket就绪条件:
同select
三、poll的优点:
不同于select使用三个位图来表示三个fdset的方式,poll使用一个pollfd的指针实现
1)polled结构包含了要发生的event和发生过的event,不再使用select”参数-值”的传递方式,
接口比select更方便
2)poll并没有最大数量限制
(但是数量过大后性能也是会下降)
四、poll的缺点
poll监听的文件描述符数目增多时:
1)性能下降
(同时连接的大量客户端一时刻只有少数处于就绪状态)
2)麻烦
(每次调用poll都要把大量的pollfd结构从用户态拷到内核中)
(poll返回后,需要轮询polled来获取就绪的描述符)
I/o多路转接之epoll
一、epoll初识:是为处理大批量句柄而做了改进的poll
二、epoll工作原理:
三、epoll的三个调用:
1、epoll_create
int epoll_create(int size)
;
创建一个epoll的句柄。
1)linux2.6.8之后,size参数是被忽略的
2 )用完之后,必须调用close()关闭。
2、epoll_ctl(操控红黑树)
int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);
3、epoll_wait(操控就绪队列)
int epoll_wait(int epfd,struct epoll epoll_event * events,int maxevents,int timeout);
总结:
epoll使用三部曲:
1)调用epoll_create创建一个epoll句柄
2)调用epoll_ctl,将要监控的文件描述符进行注册
3)调用epoll_wait,等待文件描述符就绪
四、epoll的优点
1)文件描述符无上限;
2)基于事件的就绪通知方式。(函数的读和写分开来执行)(一旦就绪,内核采用callback的回调机制,迅速激活这个文件描述符,不会影响性能)
3)维护就绪队列:当fd就绪,就被放入就绪队列,调用epoll_wait获取fd(O(1))
4)内存映射机制错误(建立过程中传了缓冲区,完成了从内核到用户数据的拷贝)
五、epoll工作方式:默认(LT)
水平触发(LT)&&边缘触发(ET)
LT:可靠,不会丢失数据
ET:更高效 有->无 才通知
少->多
LT:
1)既可用也可不用非阻塞
2)检测到socket事件时,不立刻处理,或只处理一部分
3)读1k数据,缓冲区还剩1k,在第二次调用epoll_wait时,仍然立刻返回并通知socket读事件就绪
4)data被处理完,epoll_wait才不会立刻返回
ET:
1)遇到socket事件就绪,必须立刻处理
2)读1k数据,缓冲区还剩1k,在第二次调用epoll_wait时,不会再返回
3)fd就绪后,只有一次处理机会
4)ET比LT性能更高(epoll_wait返回的次数少了很多)。
5)只支持非阻塞的读写:数据就绪只会通知一次,ET:数据就绪,需一直read,直到出错或完成为止。
六、epol使用场景
对于多连接,且多连接中只有一部分连接比较活跃时,比较适合用epoll。(QQ,微信)
七、epoll中的惊群问题
本来连接很多活跃度低,但是在某一时刻,活跃度骤升,就会导致epoll服务器压力过大。