網路程式設計學習之路3-epoll
阿新 • • 發佈:2018-12-22
書接前文,前文書講到使用多執行緒來處理tcp 連線,這次是使用單執行緒+epoll來處理tcp連線。
使用多執行緒來管理tcp連線,會增加多執行緒建立所程式碼的開銷。系統所能接受的tcp連線數 = 系統記憶體/執行緒棧大小。我用的ubuntu預設棧大小是8M。1G的空間也只能建立128個tcp連線。當然可以通過增加記憶體或者調整棧空間大小來讓單機接收更多連線。但始終不是一種高效的辦法。
epoll api
//建立epoll例項 extern int epoll_create (int __size) ; //用來增加或移除被epoll所監聽的檔案描述符 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); //等待epoll例項中註冊的事件觸發,timeout =-1表示無限等待 int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);
效果
同樣是用telnet來測試,server端列印如下
[email protected]:~/share/mycode/c++/tcp-server-epoll$ ./bin/Debug/tcp-server-epoll socket fd is 3 local ip =0.0.0.0 enter epoll_wait epoll -wait end ,active_fd_num =1 accept connect success, client port=13475ip =127.0.0.1 newsockfd=5 enter epoll_wait epoll -wait end ,active_fd_num =1 accept connect success, client port=14499ip =127.0.0.1 newsockfd=6 enter epoll_wait epoll -wait end ,active_fd_num =1 accept connect success, client port=15011ip =127.0.0.1 newsockfd=7 enter epoll_wait epoll -wait end ,active_fd_num =1 ------------------------sockfd 5 start---------------- thread: 15156 sockfd:5 recv data:fdjaidf ------------------------sockfd 5 end---------------- enter epoll_wait epoll -wait end ,active_fd_num =1 ------------------------sockfd 5 start---------------- thread: 15156 sockfd:5 recv data: ------------------------sockfd 5 end---------------- enter epoll_wait epoll -wait end ,active_fd_num =1 ------------------------sockfd 6 start---------------- thread: 15156 sockfd:6 recv data:faifda ------------------------sockfd 6 end---------------- enter epoll_wait epoll -wait end ,active_fd_num =1 ------------------------sockfd 7 start---------------- thread: 15156 sockfd:7 recv data:fjiadfa ------------------------sockfd 7 end---------------- enter epoll_wait epoll -wait end ,active_fd_num =1 ------------------------sockfd 7 start---------------- thread: 15156 sockfd:7 recv data: ------------------------sockfd 7 end---------------- enter epoll_wait
程式碼
#include <iostream> #include <arpa/inet.h> #include <err.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <thread> #include <sys/epoll.h> #define PORT 12351 #define MAXSIZE 10240 #define MAX_EVENT 100 using namespace std; void read_data(int sockfd){ printf("------------------------sockfd %d start----------------\n", sockfd); long tid = getpid(); char *buffer = (char*)malloc( 1000 * sizeof(char)); int n = read(sockfd, (void*)buffer, sizeof(buffer)/sizeof(char)); if(n ==-1){ perror("read error"); strerror(errno); std::cout<<"socket fd =" << sockfd<<std::endl; free(buffer); exit(errno); } std::cout<< "thread: "<<tid << " sockfd:"<<sockfd<<" recv data:" <<string(buffer,n)<<std::endl; free(buffer); printf("------------------------sockfd %d end----------------\n", sockfd); } int main(int args, char *argv[]) { // cout << "Hello world!" << endl; int sockfd, newsockfd; struct sockaddr_in server_addr; struct sockaddr_in client_addr; int sin_size, portnum; char buf[MAX_EVENT][MAXSIZE] = {0}; int epfd ; int active_fd_num; if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ fprintf(stderr, "create socket failed!"); strerror(errno); close(sockfd); exit(1); } std::cout<<"socket fd is " << sockfd <<std::endl; bzero(&server_addr, sizeof(struct sockaddr_in)); server_addr.sin_port = htons(PORT); server_addr.sin_family = AF_INET; // server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_addr.s_addr = inet_addr("0.0.0.0"); if( bind(sockfd, (struct sockaddr*)(&server_addr), sizeof(struct sockaddr))){ fprintf(stderr, "bind failed"); strerror(errno); close(sockfd); exit(2); } struct sockaddr_in local_addr; int len; if (getsockname(sockfd, (struct sockaddr *)&local_addr, (socklen_t* )&len) == 0) { struct sockaddr_in* sin = (struct sockaddr_in*)(&local_addr); // *port = sin->sin_port; char addr_buffer[INET_ADDRSTRLEN]; void * tmp = &(sin->sin_addr); if (inet_ntop(AF_INET, tmp, addr_buffer, INET_ADDRSTRLEN) == NULL){ cerr << "inet_ntop err"; return false; } printf("local ip =%s\n", addr_buffer); } if(listen(sockfd, 10) < 0){ fprintf(stderr,"listen failed"); strerror(errno); close(sockfd); exit(3); } sin_size = sizeof(struct sockaddr_in); //create epoll fd if((epfd = epoll_create(100)) == -1){ fprintf(stderr, "create epoll fd failed!"); strerror(errno); close(epfd); exit(1); } struct epoll_event ev, active_events[100]; ev.data.fd = sockfd; ev.events = EPOLLIN; if(epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev) == -1){ fprintf(stderr, "add sock fd failed!"); strerror(errno); close(epfd); exit(1); } while(1){ std::cout<<"enter epoll_wait" <<std::endl; active_fd_num = epoll_wait(epfd, active_events, MAX_EVENT, -1);//-1 if(active_fd_num <= 0) continue; std::cout<<"epoll -wait end ,active_fd_num =" << active_fd_num<<std::endl; for(int i =0; i<active_fd_num ; i++){ if(active_events[i].data.fd == sockfd){ if( (newsockfd = accept(sockfd, (struct sockaddr *) (&client_addr),(socklen_t*) &sin_size))< 0){ fprintf(stderr, "listen failed"); strerror(errno); exit(3); } std::cout<<"accept connect success, client port=" << client_addr.sin_port<< "ip =" <<inet_ntoa(client_addr.sin_addr)<<std::endl; std::cout<< "newsockfd=" << newsockfd<<std::endl; active_events[i].events = EPOLLIN; active_events[i].data.fd = newsockfd; if(epoll_ctl(epfd, EPOLL_CTL_ADD, newsockfd, &active_events[i]) == -1){ fprintf(stderr, "add sock fd failed!"); strerror(errno); close(epfd); exit(1); } }else { read_data(active_events[i].data.fd); } } } for(int i =0; i<MAX_EVENT ;i++){ if( active_events[i].data.fd != 0) close(active_events[i].data.fd); } return 0; }