Epoll的水平触发和边缘触发
程序员文章站
2022-06-14 11:00:06
...
Epoll水平触发和边缘触发的区别
(网上截图的,觉得写的挺好的)
水平触发的例子
Client端写HelloWorld给server,但是Server每次只读取5字节,所以当Client写10字节的内容给Server,第一次读取后,Server依然会有EPOLLIN的事件,然后读取剩下的5字节。
代码没有将已连接的connection保存在数组中或链表中,只是一个demo。
//server code
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <sys/un.h>
int listen_fd=-1;
int epoll_fd=-1;
void addEpoll(int fd){
struct epoll_event event[1];
event->events=EPOLLIN;
event->data.fd=fd;
epoll_ctl(epoll_fd,EPOLL_CTL_ADD,fd,event);
}
void removeEpoll(int fd){
struct epoll_event event[1];
event->events=0;
event->data.fd=fd;
epoll_ctl(epoll_fd,EPOLL_CTL_DEL,fd,event);
}
int main(void){
int ret;
struct sockaddr_un addr;
listen_fd =socket(AF_UNIX,SOCK_STREAM,0);
if(listen_fd<0){
printf("create socket failed \n");
return -1;
}
memset(&addr,0,sizeof addr);
addr.sun_family=AF_UNIX;
strcpy(addr.sun_path,"test");
unlink(addr.sun_path);
ret=bind(listen_fd,(struct sockaddr *)&addr,sizeof addr);
if(ret){
printf("bind socket failed\n");
return -1;
}
ret=listen(listen_fd,5);
if(ret){
printf("listen socket failed\n");
return -1;
}
epoll_fd=epoll_create(256);
if(epoll_fd<0){
printf("create epoll failed\n");
return -1;
}
addEpoll(listen_fd);
int num,i;
int client_fd;
char buf[20];
unsigned msec=10;
struct epoll_event events[256];
while(1){
//memset zero buf
memset(buf,0,20);
num=epoll_wait(epoll_fd,events,256,msec);
if(num>0){
for(i=0;i<num;i++){
if(events[i].data.fd==listen_fd){
printf("receive a connection\n");
client_fd=accept(listen_fd,NULL,NULL);
addEpoll(client_fd);
}else if(events[i].events & EPOLLHUP){
printf("receive a epollhup event\n");
removeEpoll(events[i].data.fd);
}else{
read(client_fd,&buf,5);
printf("%s\n",buf);
}
}
}else{
//printf("no event\n");
}
}
}
//client code
#include <stdio.h>
#include <stdlib.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <sys/types.h>
int main(void){
struct sockaddr_un addr;
int fd;
fd=socket(AF_UNIX,SOCK_STREAM,0);
if(fd<0){
printf("socket create failed \n");
}
memset(&addr,0,sizeof addr);
addr.sun_family= AF_UNIX;
strcpy(addr.sun_path,"test");
connect(fd,(struct sockaddr*)&addr,sizeof addr);
char* buf="helloWorld";
write(fd,buf,strlen(buf));
sleep(15);
close(fd);
}
结果
边缘触发的例子
使用与水平触发的例子相同,只是将水平触发改成边缘触发。
void addEpoll(int fd){
struct epoll_event event[1];
event->events=EPOLLIN | EPOLLET;
event->data.fd=fd;
epoll_ctl(epoll_fd,EPOLL_CTL_ADD,fd,event);
}
结果
从结果图中看到,我们只读了一次,即epoll_wait只有在第一次Client 发给server的时候触发了一次EPOLLIN,即使Server没有将
缓冲区中的内容全部读完,epoll下次也不会通知我们了。
EPOLLHUP这个事件,我们明明没有注册,但是client关闭后,server依然能接受到EPOLLHUP的事件,这个东西还是需要看源码找下原因,在水平触发中,如果不处理EPOLLHUP,将fd从epoll中移除到,那么epoll会一直会报EPOLLHUP的事件。
推荐阅读
-
详解Linux内核进程调度函数schedule()的触发和执行时机
-
Oracle触发器的作用、应用场景、语法和实例讲解
-
SQL server 数据库的索引和视图、存储过程和触发器
-
Oracle使用触发器和mysql中使用触发器的案例比较
-
Oracle数据创建虚拟列和复合触发器的方法
-
在SAP C4C里触发SAP ERP的ATP check和Credit check C4CERPSAPATP check
-
PostgreSQL的学习心得和知识总结(十二)|数据库触发器使用说明及特性总结
-
MySQL索引、触发器、常用函数、存储过程和函数、数据备份与还原的介绍
-
SQLServer的触发器介绍和创建使用教程
-
利用mysql触发器记录数据的插入和更新时间