17.2 边缘触发和条件触发

    xiaoxiao2021-03-26  59

    1. 两者区别:在于发生事件的时间点,条件触发:只要输入缓冲有数据就一直通知该事件;边缘触发:输入缓冲受到数据时仅注册一次事件。

    epoll默认以条件触发方式工作,select也是以条件触发模式工作的。

    2. 条件触发事件特性:

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #include <sys/epoll.h> #define BUF_SIZE 4 #define EPOLL_SIZE 50 void error_handling(char *message); int main(int argc, char *argv[]){ int serv_sock,clnt_sock; char buf[BUF_SIZE]; struct sockaddr_in serv_adr; struct sockaddr_in clnt_adr; socklen_t adr_sz; int str_len,i; struct epoll_event *ep_events; struct epoll_event event; int epfd,event_cnt; if(argc != 2){ printf("Usage : %s <port>\n",argv[0]); exit(1); } serv_sock = socket(PF_INET,SOCK_STREAM,0); if(serv_sock == -1){ error_handling("socket error"); } memset(&serv_adr,0,sizeof(serv_adr)); serv_adr.sin_family=AF_INET; serv_adr.sin_addr.s_addr=htonl(INADDR_ANY); serv_adr.sin_port=htons(atoi(argv[1])); if(bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1){ error_handling("bind() error"); } if(listen(serv_sock,5) == -1){ error_handling("listen() error"); } epfd = epoll_create(EPOLL_SIZE); ep_events = malloc(sizeof(struct epoll_event)*EPOLL_SIZE); event.events = EPOLLIN; event.data.fd = serv_sock; epoll_ctl(epfd,EPOLL_CTL_ADD,serv_sock,&event); while(1){ event_cnt = epoll_wait(epfd,ep_events,EPOLL_SIZE,-1); if(event_cnt == -1){ puts("epoll wait error"); break; } puts("return epoll wait"); for(i=0;i<event_cnt;i++){ if(ep_events[i].data.fd == serv_sock){ adr_sz = sizeof(clnt_adr); clnt_sock = accept(serv_sock,(struct sockaddr *)&clnt_adr,&adr_sz); event.events = EPOLLIN; event.data.fd = clnt_sock; epoll_ctl(epfd,EPOLL_CTL_ADD,clnt_sock,&event); printf("connected client : %d \n", clnt_sock); }else{ //read message str_len = read(ep_events[i].data.fd,buf,BUF_SIZE); if(str_len == 0){ //close epoll_ctl(epfd,EPOLL_CTL_DEL,ep_events[i].data.fd,NULL); close(ep_events[i].data.fd); printf("closed client %d \n",ep_events[i].data.fd); }else{ write(ep_events[i].data.fd,buf,str_len); //echo } } } } close(serv_sock); close(epfd); return 0; } void error_handling(char *message){ fputs(message,stderr); fputs("\n",stderr); exit(1); }执行结果:多次触发事件

    alex@alex-virtual-machine:/extra/tcpip/17$ ./a.out 9190 return epoll wait connected client : 5 return epoll wait return epoll wait return epoll wait return epoll wait return epoll wait return epoll wait return epoll wait return epoll wait return epoll wait3. 边缘触发

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #include <sys/epoll.h> #include <errno.h> #include <fcntl.h> #define BUF_SIZE 4 #define EPOLL_SIZE 50 void error_handling(char *message); void setnonblockingmode(int fd); int main(int argc, char *argv[]){ int serv_sock,clnt_sock; char buf[BUF_SIZE]; struct sockaddr_in serv_adr; struct sockaddr_in clnt_adr; socklen_t adr_sz; int str_len,i; struct epoll_event *ep_events; struct epoll_event event; int epfd,event_cnt; if(argc != 2){ printf("Usage : %s <port>\n",argv[0]); exit(1); } serv_sock = socket(PF_INET,SOCK_STREAM,0); if(serv_sock == -1){ error_handling("socket error"); } memset(&serv_adr,0,sizeof(serv_adr)); serv_adr.sin_family=AF_INET; serv_adr.sin_addr.s_addr=htonl(INADDR_ANY); serv_adr.sin_port=htons(atoi(argv[1])); if(bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1){ error_handling("bind() error"); } if(listen(serv_sock,5) == -1){ error_handling("listen() error"); } epfd = epoll_create(EPOLL_SIZE); ep_events = malloc(sizeof(struct epoll_event)*EPOLL_SIZE); event.events = EPOLLIN; event.data.fd = serv_sock; epoll_ctl(epfd,EPOLL_CTL_ADD,serv_sock,&event); while(1){ event_cnt = epoll_wait(epfd,ep_events,EPOLL_SIZE,-1); if(event_cnt == -1){ puts("epoll wait error"); break; } puts("return epoll wait"); for(i=0;i<event_cnt;i++){ if(ep_events[i].data.fd == serv_sock){ adr_sz = sizeof(clnt_adr); clnt_sock = accept(serv_sock,(struct sockaddr *)&clnt_adr,&adr_sz); setnonblockingmode(clnt_sock); event.events = EPOLLIN | EPOLLET; //设置成边缘触发 event.data.fd = clnt_sock; epoll_ctl(epfd,EPOLL_CTL_ADD,clnt_sock,&event); printf("connected client : %d \n", clnt_sock); }else{ //read message while(1){ str_len = read(ep_events[i].data.fd,buf,BUF_SIZE); if(str_len == 0){ //close epoll_ctl(epfd,EPOLL_CTL_DEL,ep_events[i].data.fd,NULL); close(ep_events[i].data.fd); printf("closed client %d \n",ep_events[i].data.fd); break; }else if(str_len < 0){ if(errno == EAGAIN){ //无数据可读 break; } }else{ write(ep_events[i].data.fd,buf,str_len); //echo } } } } } close(serv_sock); close(epfd); return 0; } void error_handling(char *message){ fputs(message,stderr); fputs("\n",stderr); exit(1); } void setnonblockingmode(int fd){ int flag = fcntl(fd,F_GETFL,0); //设置成非阻塞形式 fcntl(fd,F_SETFL,flag | O_NONBLOCK); }执行结果:触发一次

    alex@alex-virtual-machine:/extra/tcpip/17$ ./a.out 9191 return epoll wait connected client : 5 return epoll wait5. 条件触发与边缘触发比较:应该从服务器端实现模型角度考虑。

    边缘触发能够做到接收数据与处理数据的时间点分离。

    转载请注明原文地址: https://ju.6miu.com/read-659175.html

    最新回复(0)