select和epoll都是多路复用的实现。
select:
调用select(fds),把fds(最多1024个)从用户空间拷贝到内核空间,进程阻塞,
当socket缓冲区有数据,唤醒进程,遍历fds,处理。
epoll:
epoll_create在内核空间创建eventpoll对象(包括红黑树和就绪链表),
调用epoll_clt(fds)把fds加入到eventpoll的红黑树中,
给每个fd都向底层注册回调,
调用epoll_wait,进程阻塞,
当socket缓冲区有数据时,通过回调把红黑树对应的fd加入到就绪链表,
epoll_wait就会得到就绪链表中就绪的fds,处理。
epoll水平触发(LT)和边缘触发(ET)的区别
//水平触发 ret = read(fd, buf, sizeof(buf)); //边缘触发 while(true) { ret = read(fd, buf, sizeof(buf); if (ret == EAGAIN) break; }View Code
水平触发(LT):只要缓冲区有数据,就会触发(epoll_wait结束阻塞得到就绪列表),是默认模式。(select也是水平触发)
边缘触发(ET):只有新数据到达缓冲区才会触发,不管缓冲区有无旧数据。
实现:LT模式每次把就绪链表清空,下次有新数据到来才会调用回调把新数据的fd加入到就绪链表中。
ET模式则不会把还有数据的fd从就绪链表删掉,所以下次调epoll_wait还会触发。
因此,ET模式实际上把保证数据处理完的逻辑交给了用户,只会触发一次所以提高了效率。
-----
参考
https://bbs.gameres.com/thread_842984_1_1.html
https://blog.csdn.net/daaikuaichuan/article/details/83862311
https://www.cnblogs.com/guxuanqing/p/10570625.html