水平触发:当被监控的文件描述符上有可读写的时间发生时,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]
垂直触发只接收了客户端发来的第一个字节,并没有接收完,就不接收了。
还是代码结果一目了然。