epoll示例
书到用时方恨少,一切尽在不言中
#include <iostream> #include <sys/socket.h> #include <sys/epoll.h> #include <netinet/in.h> #include <arpa/inet.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <errno.h> #include <string.h> using namespace std; #define MAXLINE 5 #define OPEN_MAX 100 #define LISTENQ 20 #define SERV_PORT 5000 #define INFTIM 1000 void setnonblocking(int sock) { int opts; opts=fcntl(sock,F_GETFL); if(opts<0) { perror("fcntl(sock,GETFL)"); return; } opts = opts|O_NONBLOCK; if(fcntl(sock,F_SETFL,opts)<0) { perror("fcntl(sock,SETFL,opts)"); return; } } void CloseAndDisable(int sockid, epoll_event ee) { close(sockid); ee.data.fd = -1; } ssize_t socket_send(int sockfd, const char* buffer, size_t buflen) { ssize_t tmp; size_t total = buflen; const char *p = buffer; while(1) { tmp = send(sockfd, p, total, 0); if(tmp < 0) { if(errno == EINTR) return -1; if(errno == EAGAIN) { usleep(1000); continue; } return -1; } if((size_t)tmp == total) return buflen; total -= tmp; p += tmp; } return tmp; } int main() { int i, maxi, listenfd, connfd, sockfd,epfd,nfds, portnumber; char line[MAXLINE*50]; socklen_t clilen; portnumber = 5000; struct epoll_event ev,events[20]; epfd=epoll_create(256); struct sockaddr_in clientaddr; struct sockaddr_in serveraddr; listenfd = socket(AF_INET, SOCK_STREAM, 0); memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port=htons(portnumber); bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr)); listen(listenfd, LISTENQ); ev.data.fd=listenfd; ev.events=EPOLLIN|EPOLLET; epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev); maxi = 0; int bOut = 0; for ( ; ; ) { if (bOut == 1) break; nfds=epoll_wait(epfd,events,20,-1); //printf("wait %d returns\n",nfds); for(i=0;i<nfds;++i) { if(events[i].data.fd==listenfd)//如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口 { connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen); if(connfd<0){ perror("connfd<0"); return (1); } char *str = inet_ntoa(clientaddr.sin_addr); cout << "accapt a connection from " << str << endl; setnonblocking(connfd); ev.data.fd=connfd; ev.events=EPOLLIN | EPOLLET; //注册ev epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev); } else if(events[i].events & EPOLLIN) { cout << "EPOLLIN" << endl; if ( (sockfd = events[i].data.fd) < 0) continue; cout << "START READ" << endl; char * head = line; int recvNum = 0; int count = 0; bool bReadOk = false; while(1) { recvNum = recv(sockfd, head+count, MAXLINE-1, 0); if(recvNum < 0) { if(errno == EAGAIN) {//已没数据 不阻塞等待 bReadOk = true; break; } else if (errno == ECONNRESET) { CloseAndDisable(sockfd, events[i]); cout << "counterpart send out RST\n"; break; } else if (errno == EINTR) {//有数据但未读到断了,所以要接着读 continue; } else { CloseAndDisable(sockfd, events[i]); cout << "unrecovable error\n"; break; } } else if( recvNum == 0) { CloseAndDisable(sockfd, events[i]); cout << "counterpart has shut off\n"; break; } count += recvNum; if ( recvNum == MAXLINE-1) { cout << "sleeping..."<<endl; sleep(5); cout << "recvNum == MAXLINE-1\n"<<endl; continue; } else // 0 < recvNum < MAXLINE-1 { cout << "0 < recvNum < MAXLINE-1"<<endl; bReadOk = true; break; // 退出while(1),表示已经全部读完数据 } } if (bReadOk == true) { line[count] = '\0'; cout << "we have read from the client : " << line; ev.data.fd=sockfd; ev.events = EPOLLOUT | EPOLLET; epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev); } } else if(events[i].events & EPOLLOUT) // 如果有数据发送 { cout << "EPOLLOUT" << endl; const char str[] = "1234567890"; //printf("%d\n",sizeof(str)); memcpy(line, str, sizeof(str)); //cout << line << endl; printf("d %d u %u lu %lu\n",i,i,i); sockfd = events[i].data.fd; int bWritten = 0; int writenLen = 0; int count = 0; char * head = line; bWritten=socket_send(sockfd,head,strlen(head)); if (bWritten == strlen(head)) { ev.data.fd=sockfd; ev.events=EPOLLIN | EPOLLET; epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev); } } } } return 0; }
关于epoll和accept的注意点,参见http://www.ccvita.com/515.html