在网络编程中,会涉及到水平触发与边缘触发的概念,工程中以边缘触发较为常见,本文讲述了边缘触发与水平触发的概念,并给出代码示例,通过代码可以很清楚的看到它们之间的区别。
水平触发与边缘触发
水平触发(level-trggered)
只要文件描述符关联的读内核缓冲区非空,有数据可以读取,就一直发出可读信号进行通知,
当文件描述符关联的内核写缓冲区不满,有空间可以写入,就一直发出可写信号进行通知
边缘触发(edge-triggered)
当文件描述符关联的读内核缓冲区由空转化为非空的时候,则发出可读信号进行通知,
当文件描述符关联的内核写缓冲区由满转化为不满的时候,则发出可写信号进行通知
两者的区别?
水平触发是只要读缓冲区有数据,就会一直触发可读信号,而边缘触发仅仅在空变为非空的时候通知一次,举个例子:
读缓冲区刚开始是空的
读缓冲区写入2KB数据
水平触发和边缘触发模式此时都会发出可读信号
收到信号通知后,读取了1kb的数据,读缓冲区还剩余1KB数据
水平触发会再次进行通知,而边缘触发不会再进行通知
所以边缘触发需要一次性的把缓冲区的数据读完为止,也就是一直读,直到读到EGAIN(EGAIN说明缓冲区已经空了)为止,因为这一点,边缘触发需要设置文件句柄为非阻塞。
ET模式在很大程度上减少了epoll事件被重复触发的次数,因此效率要比LT模式高。epoll工作在ET模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。
这里只简单的给出了水平触发与边缘触发的处理方式的不同,边缘触发相对水平触发处理的细节更多一些,
//水平触发
ret = read(fd, buf, sizeof(buf));
//边缘触发(代码不完整,仅为简单区别与水平触发方式的代码)
while(true) {
ret = read(fd, buf, sizeof(buf);
if (ret == EAGAIN) break;
}
代码示例
通过下面的代码示例,能够看到水平触发与边缘触发代码的不同以及触发次数的不同。通过这个示例能够加深你对边缘触发与水平触发的理解。
/* echo server*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX_EVENTS 1024
#define LISTEN_PORT 33333
#define MAX_BUF 1024
// #define LEVEL_TRIGGER</