I/O复用(三)---epoll机制
来源:互联网 发布:中国的农作物产量知乎 编辑:程序博客网 时间:2024/06/05 18:42
epoll实现机制分析:
epoll是Linux特有的I/O复用函数。它在实现和使用上与select和poll有很大的差异。首先,epoll使用一组函数来完成任务,而不是单个的函数。其次,epoll把用户关心的文件描述符上的事件放在内核的一个时间表中,从而无需像select和epoll那样每次调用都要重复传入文件描述符和集或事件集。但epoll需要使用一个额外的文件描述符,来唯一标识内核中的这个事件表。而这个文件描述符使用epoll_create函数来创建。
size参数现在并不起作用,只是给内核一个提示。告诉它时间表需要多大。该函数返回的文件描述符将用作其他所有epoll系统调用的第一个参数,以指定要访问的内核事件表。
实质:epoll_create函数的返回值为epfd,每个epfd在内核中有一个对应的eventpoll结构体对象。其中关键的成员是一个就绪队列和一颗红黑树。一个fd被添加到epoll中之后,系统就会为它生成一个对应的epitem结构对象。epitem被添加到eventpoll的红黑树中。红黑树的作用是使用者调用EPOLL_CTL_MOD、EPOLL_CTL_ADD或EPOLL_CTL_DEL的时候可以迅速找到对应的就绪事件。
epoll_ctl:
epfd参数是要操作的文件描述符,op参数则指定操作类型。event参数指定事件,它是epoll_event结构体指针类型。epoll_event的定义如下:
epoll_event中的events成员描述事件类型。epoll支持的事件类型和poll基本相同。data成员用于存储用户数据。
epoll_data是一个联合体,其4个成员中使用最多的是fd和ptr。但他们不能同时使用。epoll_ctl成功时返回0,失败时返回-1并设置errno。
epitem重新添加到readylist(就绪队列)必须满足下列条件。
1.epitem上有用户关注的事件触发。
2.epitem被设置为水平触发模式(如果一个epitem被设置为边界触发则这个epitem不会被重新添加到readylist中)
epoll_wait:
epoll_wait是epoll系列系统调用的主要接口,它在一段超时时间内等待一组文件描述符上的事件。
该函数成功时返回就绪的文件描述符的个数,失败时返回-1并设置errno。
原理:
epoll_wait函数如果检测到时间,就将所有就绪的事件从内核事件表(由epfd参数指定)中复制到它的第二个参数events指向的数组中。这个数组只用于输出epoll_wait检测到的就绪事件,不想select和poll的参数是输入输出型参数,这样就极大提高了应用程序索引就绪文件描述符的效率。
代码实现:
/*************************************************************************> File Name: epoll_server.c> Author: ZX> Mail: 18829897183@163.com > Created Time: Sat 18 Mar 2017 10:21:03 PM PDT ************************************************************************/#include<stdio.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<assert.h>#include<unistd.h>#include<sys/epoll.h>#include<stdlib.h>#include<string.h>#define _SIZE_ 1024typedef struct epbuf{int fd;char buf[_SIZE_];}epbuf_t,*epbuf_p,**epbuf_pp;static epbuf_p alloc_epbuf(int fd){epbuf_p ptr = (epbuf_p)malloc(sizeof(epbuf_t));if(ptr == NULL){perror("malloc");exit(6);}ptr->fd = fd;printf("ptr->fd:%d\n",fd);return ptr;}static void delete_epbuf(epbuf_p ptr){if(ptr != NULL){free(ptr);}ptr = NULL;}int startup(const char* _ip, int _port){assert(_ip);int sock = socket(AF_INET, SOCK_STREAM, 0);if(sock < 0){perror("sock");exit(1);}int opt = 1;setsockopt(sock, SOL_SOCKET,SO_REUSEADDR, &opt, sizeof(opt));struct sockaddr_in local;local.sin_family = AF_INET;local.sin_addr.s_addr = inet_addr(_ip);local.sin_port = htons(_port);socklen_t len = sizeof(local);if(bind(sock, (struct sockaddr*)&local, len) < 0){perror("bind");exit(2);}if(listen(sock, 5) < 0){perror("listen");exit(3);}return sock;}int main(int argc, char* argv[]){if(argc != 3){printf("Usage: %s [local_ip] [local_port]",argv[0]);return 4;}int epfd = epoll_create(256);if(epfd < 0){perror("epoll_create");return 5;}int listen_sock = startup(argv[1], atoi(argv[2]));struct epoll_event _ev;_ev.events = EPOLLIN;_ev.data.ptr = alloc_epbuf(listen_sock);//_ev.data.fd = listen_sock;epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &_ev);struct epoll_event _evs[32];int max = 32;int timeout = 2000;int nums = 0;while(1){switch(nums = epoll_wait(epfd, _evs, max, timeout)){case 0:printf("timeout...\n");break;case -1:perror("epoll_wait");break;default:{printf("nums: %d\n",nums);int i = 0;for(; i<nums; i++){sleep(1);int fd = ((epbuf_p)(_evs[i].data.ptr))->fd;printf("after fd: %d\n",fd);if(fd == listen_sock && (_evs[i].events & EPOLLIN)){struct sockaddr_in peer;socklen_t len = sizeof(peer);int new_sock = accept(listen_sock, (struct sockaddr*)&peer, &len);printf("after accept,new_sock:%d\n",new_sock);if(new_sock < 0){perror("accept");continue;}else if(new_sock > 0){printf("get a new client# port %d\n",ntohs(peer.sin_port));_ev.events = EPOLLIN;//_ev.data.fd = new_sock;_ev.data.ptr = alloc_epbuf(new_sock);epoll_ctl(epfd, EPOLL_CTL_ADD, new_sock, &_ev);}}//ifelse if(fd != listen_sock && (_evs[i].events & EPOLLIN)){char* buf = ((epbuf_p)(_evs[i].data.ptr))->buf;printf("read fd: %d\n",fd);ssize_t _s = read(fd, buf, _SIZE_-1);if(_s > 0){//succeed, change file descriptorbuf[_s] = 0;printf("%s\n", buf);_ev.events = EPOLLOUT;epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &_ev);}else if(_s == 0){printf("client is quit!\n");delete_epbuf(_evs[i].data.ptr);_evs[i].data.ptr = NULL;epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);close(fd);}else{perror("read");continue;}}//else if read file descriptorelse if(fd != listen_sock && (_evs[i].events & EPOLLOUT)){printf("write:\n");const char* msg = "HTTP/1.0 200 OK \r\n\r\n<html><h1>HELLO WORLD!</h1></html>\n";write(fd, msg, strlen(msg));delete_epbuf(_evs[i].data.ptr);_evs[i].data.ptr = NULL;epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);close(fd);}//else if write file descriptor}//for}break;}//switch}//whilereturn 0;}
- I/O复用(三)---epoll机制
- epoll I/O复用
- I/O复用-epoll
- I/O复用epoll
- I/O复用------epoll
- Linux I/O复用 epoll
- I/O复用:epoll函数
- epoll 实现I/O复用
- 三种 I/O 复用(select poll epoll)的优缺点总结 & epoll 为何如此高效
- 浅谈I/O复用:select、poll、epoll
- I/O复用 select poll epoll
- Linux I/O复用:select ,poll,epoll
- I/O复用-epoll系列系统调用
- 多路I/O复用(select epoll)
- Linux复用I/O-epoll-server代码
- I/O复用select、poll、epoll
- epoll I/O 多路复用
- I/O Multiplexing & epoll
- 第八,九章
- E-charts之一个与页面多个图表并且自适应的方案
- Git
- Linux下命令行安装配置android sdk
- 常规双击回退键退出程序
- I/O复用(三)---epoll机制
- java连接ubuntu中的redis出错
- C++——math.h
- 安装xhprof 和 xhgui参考文章总结
- 173. Binary Search Tree Iterator(unsolved)
- Navicat Premium for Mac 11.1.8 免费中文破解版下载
- 如何让孩子爱上设计模式 ——23.状态模式(State Pattern)
- 天梯-红色警报
- Linux ps命令详解与示例说明