水平和边缘触发实战

             水平触发:当被监控的文件描述符上有可读写的时间发生时,epoll_wait会通知处理程序去读写,如果你没有读写完,下次epoll_wait就会再直通知你。

              垂直触发:当被监控的文件描述符上有可读写时间发生时,epoll_wait会通知处理程序去读写,如果你没有读写玩,下次epoll_wait就不会在通知你。

直接看代码,源地址代码我略微改了一下:

代码地址:http://blog.csdn.net/stpeace/article/details/73692958

水平触发:ev.events = EPOLLIN        垂直触发: ev.events = EPOLLIN|EPOLLET;//垂直触发 

服务端:

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdarg.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <netinet/tcp.h> 
#include <sys/epoll.h>

#define MAXLINE 4096
#define BACKLOG 100  


int main()    
{  
    int iListenSock = socket(AF_INET, SOCK_STREAM, 0);  
    sockaddr_in addr;  
    memset(&addr, 0, sizeof(addr));

    inet_aton("0.0.0.0", &addr.sin_addr);  
    addr.sin_family = AF_INET;  
    addr.sin_port = htons(8888);  
  
    int iOpt = 1;  
    setsockopt(iListenSock, SOL_SOCKET, SO_REUSEADDR, &iOpt, sizeof(iOpt)); // 标配  
    bind(iListenSock, (sockaddr*)&addr, sizeof(addr));  
    listen(iListenSock, BACKLOG);  

	
    epoll_event ev;  
    ev.data.fd = iListenSock;  
    //ev.events = EPOLLIN|EPOLLET;//垂直触发
    ev.events = EPOLLIN;//水平触发 
    epoll_event events;  
  
    int epollFD = epoll_create(BACKLOG + 1);   // 告诉内核监测的数目, 返回的epollFD为epoll管理句柄  
    epoll_ctl(epollFD, EPOLL_CTL_ADD, iListenSock, &ev);  // 将ev和对应的iListenSock添加到epoll句柄,用于被epollFD管理  
    while(1)   
    {  
        int timeoutMS = -1; // 永不超时  
        int nfds = epoll_wait(epollFD, &events, BACKLOG + 1, timeoutMS);   // events和nfds是一对输出值  
        printf("nfds is %d\n", nfds);  
          
        if(events.data.fd == iListenSock)         // 用于监听客户端连接的socket  
        {    
            int iConnSock = accept(iListenSock, NULL, NULL);  
            if (iConnSock < 0)  
            {  
                continue;  
            }  

            ev.data.fd = iConnSock;  
            //ev.events = EPOLLIN|EPOLLET;//垂直触发
			ev.events = EPOLLIN;//水平触发 
            epoll_ctl(epollFD, EPOLL_CTL_ADD, iConnSock, &ev);  // 将ev和对应的iConnSock添加到epoll句柄,用于被epollFD管理  
            printf("new sock came, fd is %d\n", iConnSock);  
        }   
        else   
        {  
            int iConnSock = events.data.fd;      // 用于通信的socket  
            char szBuf[2] = {0};  //使得每次只读一个字节的数据
            int recvLen = recv(iConnSock, szBuf, sizeof(szBuf) - 1, 0);  
            if (recvLen > 0)   
            {    
                printf("recv data [%s] from fd [%d]\n", szBuf, iConnSock);  
            }  
            else if(0 == recvLen)  
            {    
                ev.data.fd = iConnSock;  
                epoll_ctl(epollFD, EPOLL_CTL_DEL, iConnSock, &ev);  //删除ev中对应的句柄
                close(iConnSock);   
            }  
            else  
            {  
                ev.data.fd = iConnSock;  
                epoll_ctl(epollFD, EPOLL_CTL_DEL, iConnSock, &ev);//删除ev中对应的句柄  
                close(iConnSock);    
            }  
        }       
    }    
      
    close(epollFD);  
    close(iListenSock);  
    return 0;  
}
客户端:

#include <unistd.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netdb.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <ctype.h>  
#include <errno.h>  
#include <malloc.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <sys/ioctl.h>  
#include <stdarg.h>  
#include <fcntl.h> 
#include <error.h>
  
int main()  
{ 
     char sendBuf[20]="1234567890"; 
     int ret = 0;
     int sockClient = socket(AF_INET, SOCK_STREAM, 0);  
  
     struct sockaddr_in addrSrv;  
     addrSrv.sin_addr.s_addr=inet_addr("127.0.0.1");
     addrSrv.sin_family = AF_INET;  
     addrSrv.sin_port = htons(8888); 

     ret=connect(sockClient, ( const struct sockaddr *)&addrSrv, sizeof(struct sockaddr_in)); 

     send(sockClient,sendBuf,strlen(sendBuf),0);

     getchar();  
     close(sockClient);  
  
     return 0;  
} 
先运行服务端,再运行客户端。服务端每次接受一个字节的数据,水平触发的服务端结果如下:

[mapan@localhost IO]$ ./server 
nfds is 1
new sock came, fd is 5
nfds is 1
recv data [1] from fd [5]
nfds is 1
recv data [2] from fd [5]
nfds is 1
recv data [3] from fd [5]
nfds is 1
recv data [4] from fd [5]
nfds is 1
recv data [5] from fd [5]
nfds is 1
recv data [6] from fd [5]
nfds is 1
recv data [7] from fd [5]
nfds is 1
recv data [8] from fd [5]
nfds is 1
recv data [9] from fd [5]
nfds is 1
recv data [0] from fd [5]

服务端对客户端发来数据分10次接收了,epoll_wait返回了10次也就接收了10次。

注释代码中的水平触发那一行,解开对垂直触发那行的注释,客户端不变,编译运行。垂直触发的服务端结果如下:

[mapan@localhost IO]$ ./server 
nfds is 1
new sock came, fd is 5
nfds is 1
recv data [1] from fd [5]

垂直触发只接收了客户端发来的第一个字节,并没有接收完,就不接收了。

还是代码结果一目了然。






          



猜你喜欢

转载自blog.csdn.net/ma2595162349/article/details/79017110