epoll水平触发与边缘触发
把高电平看作文件描述符是可读或可写状态,低电平黑色表示不可读或不可写,epoll_wait的水平触发就是蓝色的时候epoll_wait就会被触发,而边缘触发就是红色的时候epoll_wait会触发,且只会触发一次。比如,client_fd在某时刻充入数据,epoll_wait第一次检测到,水平、边缘都会触发,进程开始读数据,若数据没有读完。那么水平触发会在下一次运行到epoll_wait的时候再触发一次,而边缘触发就不会。
水平触发下,可能会多次调用epoll_wait导致效率低下。而边缘触发下,如果第一次触发没有读干净缓冲区,那么就只能等到下一次冲入数据才能触发epoll_wait读出上一次的数据,所以在边缘触发下,必须一次将缓冲区的数据读干净。
方法就是设置epoll_event的events设置为 EPOLLET ,在死循环里一直读client_fd,但读完后read系统调用会阻塞,所以要将client_fd设置为非阻塞:
int flags = fcntl(client_fd, F_GETFL);//获取的cfd的标志位
flags |= O_NONBLOCK;
fcntl(client_fd,F_SETFL,flags);
struct epoll_event e;
e.events = EPOLLIN | EPOLLET;
...
当read读非阻塞文件描述符读干净的时候,不会阻塞,而是返回-1并且把errno设置为EAGAIN,这时就可以跳出死循环。
while (1)
{
char buf[SIZE] = "";
int n = read(fd, buf, SIZE);
if (n < 0)
{
if (errno == EAGAIN)
{
printf("读完了\n");
break;
}
Close(fd);
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
perror("read");
return 1;
}
else if (0 == n) // 套接字关闭
{
printf("client close\n");
Close(fd);
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
break;
}
else
{
Write(STDOUT_FILENO, buf, SIZE);
Write(fd, buf, n);
}
}

浙公网安备 33010602011771号