本文主要是谈为什么Epoll
中ET(边缘出发)
为什么需要搭配非阻塞IO
的原因
文章参考:
阻塞IO
当我们去对于一个
阻塞文件描述符
进行读取数据的时候,如果该文件描述符上没有数据可以进行读取,那么就会卡在调用的函数上面直到有数据可以进行读取。同样,如果我们对于一个
阻塞文件描述符号
进行写操作的时候,如果该缓冲区没有地方可写,那么就会卡在调用函数上直到有数据可写。当然阻塞IO不仅仅是读写,我们称
阻塞的文件描述符
为阻塞IO
,称非阻塞的文件描述符
为非阻塞IO
。Socket中可能阻塞的API:accept, recv,connect,send
非阻塞IO
非阻塞IO就是当你去读写一个
非阻塞文件描述符
的时候,无论是否可读写都会 立即返回结果。
成功:返回对应的结果。
失败:设置对应的errno
总之不会卡在这个函数
Level_triggered
当被监控的文件描述符上我们期待的事件触发了,
epoll_wait()
会通知程序进行操作。
- 如果本次没有将数据操作完成,那么下次调用
epoll_wait()
会不断的提醒你,如果你并不是很关心部分文件描述符的话,就会造成大量的浪费
Edge_triggered
当被监控的文件描述符有可操作的时间发生时,
epoll_wait()
会通知程序进行读写。如果本次没有操作完,下一次也不会通知你,只会通知你一次(因此我们需要尽量一次读取完)
为什么ET搭配非阻塞IO
如果我们一次读的数据很大,超过了我们的缓冲区大小我们就需要
while
➕recv
循环读取
- 如果是
阻塞IO
➕while
循环,当我们最后一个数据读取完之后是跳不出循环的
while(1){int len = recv();}
最后一次读不到进行了阻塞,卡在这了
- 如果是
非阻塞IO
➕while
循环,当数据读取完之后recv就会立即返回-1,并且将errno
进行设置,不会被卡在这里,性能提升