欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Epoll的水平触发和边缘触发

程序员文章站 2022-06-14 11:00:06
...

Epoll水平触发和边缘触发的区别  

   (网上截图的,觉得写的挺好的)

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);
}

	
	

结果

     Epoll的水平触发和边缘触发

 

边缘触发的例子

      使用与水平触发的例子相同,只是将水平触发改成边缘触发。

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的水平触发和边缘触发

从结果图中看到,我们只读了一次,即epoll_wait只有在第一次Client 发给server的时候触发了一次EPOLLIN,即使Server没有将

缓冲区中的内容全部读完,epoll下次也不会通知我们了。

 

EPOLLHUP这个事件,我们明明没有注册,但是client关闭后,server依然能接受到EPOLLHUP的事件,这个东西还是需要看源码找下原因,在水平触发中,如果不处理EPOLLHUP,将fd从epoll中移除到,那么epoll会一直会报EPOLLHUP的事件。

 

相关标签: Linux

上一篇: 五种IO模型

下一篇: Drawable