特色是,读完缓冲区后,若是缓冲区还有内容的话,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)); } } } }