什么是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有个感性认识。