什麼是epoll?簡單來講,就是替代select的一種方法。如果不知到select是什麼,就不用往下看了。
為什麼要替換掉select?大家說,原因有兩個:
1)Select有連結數量限制,epoll沒有。
2)select在處理大兩併發時效率低。
關於第一個原因,搜了下結果如下:
我本人也曾經在專案中用過select和epoll,對於select,感觸最深的是linux下select最大數目限制(windows 下似乎沒有限制),每個程式的select最多能處理FD_SETSIZE個FD(檔案控制程式碼), 如果要處理超過1024個控制程式碼,只能採用多程式了。 常見的使用slect的多程式模型是這樣的: 一個程式專門accept,成功後將fd通過unix socket傳遞給子程式處理,父程式可以根據子程式負載分派。曾經用過1個父程式+4個子程式 承載了超過4000個的負載。 這種模型在我們當時的業務執行的非常好。epoll在連線數方面沒有限制,當然可能需要使用者呼叫API重現設定程式的資源限制。
第二個原因,作者在部落格裡也做了介紹。select最終呼叫是net/ipv4/tcp.c,一直在做輪尋;而epoll則是等待事件發生時,告訴程式現在的socket是可讀還是可寫。
對上面內容哦你感興趣的可以戳這裡:http://www.cppblog.com/feixuwu/archive/2010/07/10/119995.html
瞭解就這麼多,很可能是錯的,今天只是敲了下demo程式碼,暫時放這裡。
//server.c #include <stdio.h> #include <string.h> #include <fcntl.h> #include <sys/epoll.h> #include <sys/socket.h> #include <netinet/in.h> #define MAX_SOCKET 10000 void add_event(int epfd, int fd, struct epoll_event *event) { epoll_ctl(epfd, EPOLL_CTL_ADD, fd, event); } void mod_event(int epfd, int fd, struct epoll_event *event) { epoll_ctl(epfd, EPOLL_CTL_MOD, fd, event); } void del_event(int epfd, int fd, struct epoll_event *event) { epoll_ctl(epfd, EPOLL_CTL_DEL, fd, event); } int init_listen(int epfd, int port) { int listenfd = socket(AF_INET, SOCK_STREAM, 0); fcntl(listenfd, F_SETFL, O_NONBLOCK); struct epoll_event event; event.data.fd = listenfd; event.events = EPOLLIN | EPOLLET; add_event(epfd, listenfd, &event); struct sockaddr_in serveraddr; memset(&serveraddr, 0, sizeof(struct sockaddr_in)); serveraddr.sin_family = AF_INET; inet_aton("127.0.0.1",&(serveraddr.sin_addr)); serveraddr.sin_port = htons(port); bind(listenfd, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr_in)); listen(listenfd, 10); return listenfd; } void accept_conn(int epfd, int listenfd) { printf("connection begin...\n"); socklen_t length; struct sockaddr_in clientaddr; memset( &clientaddr, 0, sizeof(struct sockaddr_in)); int fd = accept(listenfd, (struct sockaddr *)&clientaddr, &length); fcntl(fd, F_SETFL, O_NONBLOCK); printf("connected...\n"); char *clientip =inet_ntoa(clientaddr.sin_addr); if(clientip == NULL) printf("error!\n"); unsigned short clientport = ntohs(clientaddr.sin_port); // printf("client connected: %s:%d\n",clientip, clientport); struct epoll_event event; event.data.fd = fd; event.events = EPOLLIN | EPOLLET; add_event(epfd, fd, &event); } void recv_data(int epfd, int fd) { char buffer[1024]; memset(buffer, 0, sizeof(buffer)); ssize_t count = read(fd, buffer, sizeof(buffer)); if (count <= 0){ close(fd); return; } printf("fd %d recv: %s \n", fd, buffer); struct epoll_event event; event.data.fd = fd; event.events = EPOLLOUT | EPOLLET; mod_event(epfd, fd, &event); } void send_data(int epfd, int fd) { char buffer[1024]; static int i=0; memset(buffer, 0, sizeof(buffer)); i++; sprintf(buffer, "hello fd %d,i=%d", fd,i); ssize_t count = write(fd, buffer, strlen(buffer)); if (count <= 0){ close(fd); return; } printf("fd %d send: %s\n", fd, buffer); struct epoll_event event; event.data.fd = fd; event.events = EPOLLIN | EPOLLET; mod_event(epfd, fd, &event); } int main() { int port = 12345; int epfd = epoll_create(MAX_SOCKET); int listenfd = init_listen(epfd, port); printf("fd %d listen: %d\n", listenfd, port); while (1) { printf("epoll_wait.. \n"); struct epoll_event events[20]; int fds = epoll_wait(epfd, events, 20, 5000); printf("epoll_wait fds:%d\n", fds); int i; for (i = 0; i < fds; i++){ int fd = events[i].data.fd; if (fd == listenfd){ printf("accept_conn...\n"); accept_conn(epfd, listenfd); continue; } if (events[i].events & EPOLLIN) { printf("recv_data fd: %d\n", fd); recv_data(epfd, fd); } if (events[i].events & EPOLLOUT) { printf("send_data fd; %d\n", fd); send_data(epfd, fd); } } } close(epfd); }
再貼個client:
/client #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> int main() { int sockfd; int len; int result; char ch[20]={'1','2','3'}; sockfd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in address; address.sin_family = AF_INET; // strcpy(address.sun_path, "server_socket"); inet_aton("127.0.0.1",&(address.sin_addr)); len = sizeof(address); address.sin_port = htons(12345); result = connect(sockfd, (struct sockaddr *)&address, len); if(result == -1) { perror("oops; connect failed"); exit(1); } write(sockfd, ch, 4); read(sockfd, ch, 5); printf("char from server = %s \n", ch); close(sockfd); exit(0); }
偶得空閒,只為對epool有個感性認識。