最近打算写一个WebServer,又对epoll(ET)模式有了新的理解,记录一下。
epoll(ET)必须使用非阻塞socket的原因:
- 而如果你的文件描述符如果不是非阻塞的,那这个一直读或一直写势必会在最后一次阻塞。这样就不能在阻塞在epoll_wait上了,造成其他文件描述符的任务饿死。
epoll的两种模式LT和ET
level-trigger
模式下只要某个socket
处于readable/writable
状态,无论什么时候进行epoll_wait
都会返回该socket
edge-trigger
模式下只有某个socket
从unreadable
变为readable
或从unwritable
变为writable
时,epoll_wait
才会返回该socket
。
所以,在epoll的ET模式下,正确的读写方式为:
- 只要可读,就一直读,直到
errno = EAGAIN
或返回0 - 只要可写,就一直写,直到
errno = EAGAIN
或数据发送完
考虑这种情况:
多个连接同时到达,服务器的 TCP 就绪队列瞬间积累多个就绪连接,由于是边缘触发模式,epoll 只会通知一次,accept 只处理一个连接,导致 TCP 就绪队列中剩下的连接都得不到处理。
- 解决办法是用 while 循环抱住 accept 调用,处理完 TCP 就绪队列中的所有连接后再退出循环。
如何知道是否处理完就绪队列中的所有连接呢?
- accept 返回 -1 并且 errno 设置为 EAGAIN 就表示所有连接都处理完。