特色是,讀完緩衝區後,若是緩衝區還有內容的話,epoll_wait函數還會返回,直到把緩衝區所有讀完。c++
特色是,讀完緩衝區後,無論緩衝區還有沒有內容,epoll_wait函數都不會再返回,直到對端再一次發送信息過來。估計有的讀者朋友會想到用while去讀,可是有個致命的問題,由於文件描述符是阻塞的,因此當所有讀完後,進程就會阻塞在recv函數那裏,就不可以再處理別的鏈接了。windows
特色是,讀完緩衝區後,無論緩衝區還有沒有內容,epoll_wait函數都不會再返回,直到對端再一次發送信息過來。可是能夠事先用fcntl把文件描述符設置成非阻塞的方式,讓後用while一直去讀,當所有讀完後,recv函數也不會阻塞。數組
ET的epoll(非阻塞)的例子:微信
#include <stdio.h> #include <sys/epoll.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <errno.h> int main(int argc, char** argv){ int port = atoi(argv[1]); int lfd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; bind(lfd, (struct sockaddr*)&addr, sizeof(addr)); listen(lfd, 5); int efd = epoll_create(10); struct epoll_event re; re.events = EPOLLIN; re.data.fd = lfd; epoll_ctl(efd, EPOLL_CTL_ADD, lfd, &re); struct epoll_event events[100]; while(1){ int ret = epoll_wait(efd, events, 100, -1); printf("======================wait=======\n"); if(ret == -1){ perror("epoll_wait"); exit(1); } for(int i = 0; i < ret; ++i){ if(events[i].data.fd == lfd){ int cfd = accept(lfd, NULL, NULL); int flags = fcntl(cfd, F_GETFL); flags |= O_NONBLOCK; fcntl(cfd, F_SETFL, flags); struct epoll_event re; re.events = EPOLLIN | EPOLLET; re.data.fd = cfd; epoll_ctl(efd, EPOLL_CTL_ADD, cfd, &re); break; } char buf[3]; int ret; while((ret = recv(events[i].data.fd, buf, sizeof buf, 0)) > 0){ write(STDOUT_FILENO, buf, ret); } if(ret == 0){ epoll_ctl(efd, EPOLL_CTL_DEL, events[i].data.fd, NULL); close(events[i].data.fd); printf("client disconnet\n"); } else if(ret == -1 && errno == EAGAIN){ printf("read over\n"); } } } }
poll函數例子:socket
#include <stdio.h> #include <poll.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char** argv){ int port = atoi(argv[1]); int lfd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; bind(lfd, (struct sockaddr*)&addr, sizeof(addr)); listen(lfd, 5); struct pollfd pfd[1024]; for(int i = 0; i < 1024; ++i){ pfd[i].fd = -1; } pfd[0].fd = lfd; pfd[0].events = POLLIN; nfds_t maxfd = 0; while(1){ int ret = poll(pfd, maxfd + 1, -1); printf("--------------poll------\n"); if(pfd[0].revents & POLLIN){ int cfd = accept(lfd, NULL, NULL); for(int i = 0; i < 1024; ++i){ if(pfd[i].fd == -1){ pfd[i].fd = cfd; pfd[i].events = POLLIN; maxfd++; break; } } continue; } for(int i = 0; i <= maxfd; ++i){ if(pfd[i].revents & POLLIN){ char buf[64]; int ret = recv(pfd[i].fd, buf, sizeof buf, 0); if(ret == 0){ pfd[i].fd = -1; close(pfd[i].fd); printf("client is disconnet\n"); } else{ write(STDOUT_FILENO, buf, ret); } } } } }
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <arpa/inet.h> #include <sys/time.h> #include <unistd.h> int main(){ int fd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(12345); bind(fd, (struct sockaddr*)&addr, sizeof(addr)); listen(fd, 5); fd_set readers, temp; FD_ZERO(&readers); FD_ZERO(&temp); FD_SET(fd, &readers); int maxfd = fd; int selret = 0; char rbuf[1024] = {0}; while(1){ temp = readers; selret = select(maxfd + 1, &temp, NULL, NULL, NULL); if(FD_ISSET(fd, &temp)){ //server int cfd = accept(fd, NULL, 0); maxfd = cfd; FD_SET(cfd, &readers); maxfd = maxfd < cfd ? cfd : maxfd; continue; } //client for(int i = fd + 1; i <= maxfd; ++i){ if(FD_ISSET(i, &temp)){ int ret = read(i, rbuf, sizeof(rbuf)); printf("recv:%s\n", rbuf); if(ret == 0){ FD_CLR(i, &readers); } ret = write(i, rbuf, sizeof(rbuf)); } } } }