同步阻塞IO
linux read和write函数,调用时阻塞,直到数据读取完成或写入成功
同步非阻塞IO
和同步阻塞IO的API一样,打开fd时带有O_NONBLOCK参数,如果数据没有准备好,直接返回不阻塞,需要应用系统不断轮询
IO多路复用
三种方法 select \poll \ epoll
select linux api(int maxfdps,fd_set *readfds, fd_set *writefds,fd_set *exceptfds..)
fd是一个int值,所以fd_set其实是一个bit数组,每一位标识一个fd是否有读事件或写事件发生
第一个参数是readfds或writefds下标最大值+1,因为fd从0开始,+1才表示这个数
返回结果还在readfds和writefds里,操作系统会重置所有bit位,告知应用那个fd上有事件,应用程序需要自己遍历0到maxfds-1,然后执行read或write操作
每次select调用用,在下次调用前要重新维护readfds和writefds
poll
int poll (struct pollfd * fds, unsigned int nfds,int timeout); struct pollfd { int fd;short events; short revents; }
和select 一样,需要将fd数据传进度,每次fd数组在用户和内核态传递,影响效率
epoll linux系统中性能最好的多路复用模型
epoll 传递epfd,是一个数字,把fd数组关联到尚敏每次向内核传递的是epfd这个数字
三个步骤 事件注册 轮询事件是否就绪 执行IO操作
事件注册 accept read write
轮询事件是否就绪
执行IO操作
异步IO 读写由操作系统完成
windows的IOCP
asio 是一个上层架构层的“异步IO”,或者模拟处理的异步IO,底层在Linux系统上还是使用epoll实现,在这里“异步”,就是读写由底层框架或系统完成,完成以后,通知应用程序
linux aio,但是不太成熟
Reactor和Proactor模式
Reactor 模式 主动模式。应用系统不断轮询操作系统或框架、IO是否就绪。linux系统的select、poll、epoll,Java中的NIO 都属于这种模式
Proactor 模式 被动模式。 应用程序把read和write函数操作全部交给操作系统,实际IO由操作系统或框架完成,之后再回调应用。asio库就是Proactor模式
select、epoll的LT和ET
LT(水平触发)模式
读缓冲区只要不为空,一直触发读事件;写缓冲区不满,一直触发写事件;
LT模式下避免写的死循环,一般写满的概率小,如果无数据可写,要取消写事件。
Java NIO用的是epoll的LT模式
ET(边缘触发\状态触发)模式
读缓冲区状态从空转为非空触发一次;写缓冲区从满到非满触发一次;
ET模式要避免short read。用户收到100字节,只读取了50字节,剩下50字节也不会再触发事件,一定要不读缓冲区数据一次性读完。容易漏事件,一次触发没有处理好,就没有第二次机会了