【Nginx】epoll事件驱动模块
Linux 2.6版本号之后加入了epoll函数接口。
使得最大并发数量能够达到百万级。
epoll的使用方法例如以下:
- 调用epoll_create建立一个epoll对象。
- 调用epoll_ctl向epoll对象中加入连接套接字。
- 调用epoll_wait收集发生事件的连接。
- struct rb_root rbr; // 一棵红黑树。保存全部通过epoll_ctl加入进来的须要监控的事件
- struct list_head rdllist; // 一个双向链表,保存将要通过epoll_wait返回的、满足条件的事件
当有事件就绪时。rdllist不为空,并通过epoll_wait函数将该链表返回用户空间。
首先是决定解析哪些配置项的ngx_command_t结构体数组:
typedef struct {ngx_uint_t events; /* epoll_wait的參数3:一次最多能够返回的事件数 */ngx_uint_t aio_requests;
} ngx_epoll_conf_t;
static ngx_command_t ngx_epoll_commands[] = {/* epoll_wait系统调用一次最多能够返回的事件数 */{ ngx_string("epoll_events"),NGX_EVENT_CONF|NGX_CONF_TAKE1,ngx_conf_set_num_slot, /* 提前定义方法解析配置项 */0,offsetof(ngx_epoll_conf_t, events),NULL },/* 异步I/O相关 */{ ngx_string("worker_aio_requests"),NGX_EVENT_CONF|NGX_CONF_TAKE1,ngx_conf_set_num_slot, /* 提前定义方法解析配置项 */0,offsetof(ngx_epoll_conf_t, aio_requests),NULL },ngx_null_command
};
static ngx_str_t epoll_name = ngx_string("epoll");
ngx_event_module_t ngx_epoll_module_ctx = {&epoll_name, /* "epoll" */ngx_epoll_create_conf, /* 创建存储配置项的结构体 */ngx_epoll_init_conf, /* 解析完配置项后调用的函数 *//* ngx_event_actions_t */{ngx_epoll_add_event, /* add an event */ngx_epoll_del_event, /* delete an event */ngx_epoll_add_event, /* enable an event */ngx_epoll_del_event, /* disable an event */ngx_epoll_add_connection, /* add an connection */ngx_epoll_del_connection, /* delete an connection */NULL, /* process the changes */ngx_epoll_process_events, /* process the events */ngx_epoll_init, /* init the events */ngx_epoll_done, /* done the events */}
};
- 调用epoll_create创建epoll对象。
- 创建event_list数组接收从内核传过来的事件。
static int ep = -1; // epoll对象描写叙述符
static struct epoll_event *event_list; // 作为epoll_wait的參数。接收从内核传过来的事件
static ngx_uint_t nevents; // 可以返回的事件最大数目,同一时候也是event_list数组大小
/* 在ngx_event_core_module中调用,主要完毕两件事情:* 1、调用epoll_create方法创建epoll对象* 2、创建event_list数组用于从内核接收发生的事件*/
static ngx_int_t
ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
{ngx_epoll_conf_t *epcf;/* 获取存储配置项的结构体 */epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module);if (ep == -1) {/* 系统调用创建epoll对象,參数表示须要处理的事件的大致数目* Linux内核中不处理这个參数*/ep = epoll_create(cycle->connection_n / 2);
#if (NGX_HAVE_FILE_AIO)/* 异步I/O相关 */ngx_epoll_aio_init(cycle, epcf);
#endif}if (nevents < epcf->events) {if (event_list) {ngx_free(event_list);}/* 初始化event_list数组。数组大小是配置项epoll_events的參数 */event_list = ngx_alloc(sizeof(struct epoll_event) * epcf->events, cycle->log);}/* nevents相同是epoll_events配置项的參数 */nevents = epcf->events;/* 指明读写I/O的方法 */ngx_io = ngx_os_io;/* ngx_event_actions是个全局的ngx_event_actions_t结构体* 用于存储事件模块的10个函数接口*/ngx_event_actions = ngx_epoll_module_ctx.actions;
#if (NGX_HAVE_CLEAR_EVENT)ngx_event_flags = NGX_USE_CLEAR_EVENT // 使用epoll的边缘触发模式
#elsengx_event_flags = NGX_USE_LEVEL_EVENT // 使用epoll的水平触发模式
#endif|NGX_USE_GREEDY_EVENT|NGX_USE_EPOLL_EVENT;return NGX_OK;
}
/* 把一个感兴趣的事件加入到epoll中 */
static ngx_int_t
ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
{int op;uint32_t events, prev;ngx_event_t *e;ngx_connection_t *c;struct epoll_event ee;/* 每一个事件的data成员都存放着其相应的ngx_connection_t连接 */c = ev->data;/* events代表事件类型。在以下设置 */events = (uint32_t) event;if (event == NGX_READ_EVENT) { /* 写事件 */e = c->write;prev = EPOLLOUT;
#if (NGX_READ_EVENT != EPOLLIN|EPOLLRDHUP)events = EPOLLIN|EPOLLRDHUP;
#endif} else { /* 读事件 */e = c->read;prev = EPOLLIN|EPOLLRDHUP;
#if (NGX_WRITE_EVENT != EPOLLOUT)events = EPOLLOUT;
#endif}/* 依据是否为活跃事件确定是改动还是加入事件 */if (e->active) {op = EPOLL_CTL_MOD; /* 改动epoll中的事件 */events |= prev;} else {op = EPOLL_CTL_ADD; /* 加入新事件到epoll中 */}/* 设置事件类型 */ee.events = events | (uint32_t) flags;/* data的ptr成员指向一个连接,同一时候把最低位设置为instance标志,事件分发程序将这个标志提取出来 */ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);/* 调用epoll_ctl方法加入或改动事件* 參数1:epoll对象描写叙述符* 參数2:表示要运行的操作* EPOLL_CTL_ADD:加入新事件到epoll中* EPOLL_CTL_MOD:改动epoll中的事件* EPOLL_CTL_DEL:删除epoll中的事件* 參数3:待监听的连接套接字* 參数4:描写叙述事件的结构体epoll_event*/if (epoll_ctl(ep, op, c->fd, &ee) == -1) {ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,"epoll_ctl(%d, %d) failed", op, c->fd);return NGX_ERROR;}/* 改动active标志。表示当前事件是活跃的 */ev->active = 1;return NGX_OK;
}
/* 收集、分发事件 */
static ngx_int_t
ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{int events;uint32_t revents;ngx_int_t instance, i;ngx_uint_t level;ngx_err_t err;ngx_event_t *rev, *wev, **queue;ngx_connection_t *c;/* NGX_TIMER_INFINITE == INFTIM *//* 等待获取事件,最长等待时间为timer以保证时间可以得到更新* 參数1:epoll对象描写叙述符* 參数2:保存返回的就绪事件数组* 參数3:可以返回的最大事件数目* 參数4:最长等待时间* 返回值:就绪事件个数*/events = epoll_wait(ep, event_list, (int) nevents, timer);err = (events == -1) ? ngx_errno : 0;if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {ngx_time_update(); /* 更新时间 */}....if (events == 0) {if (timer != NGX_TIMER_INFINITE) {return NGX_OK;}return NGX_ERROR;}ngx_mutex_lock(ngx_posted_events_mutex);/* 遍历本次返回的全部事件 */for (i = 0; i < events; i++) {c = event_list[i].data.ptr; /* ptr指向事件相应的连接 *//* 提取出instance标志 */instance = (uintptr_t) c & 1;/* 屏蔽最后一位计算出真正的连接对象的地址 */c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);/* 取出读事件 */rev = c->read;/* 推断这个读事件是否过期 */if (c->fd == -1 || rev->instance != instance)continue; /* 以过期,不处理 *//* 获得事件类型 */revents = event_list[i].events;..../* 假设是读事件且该事件是活跃的 */if ((revents & EPOLLIN) && rev->active){..../* 延后处理这批事件 */if (flags & NGX_POST_EVENTS) {/* 依据是新连接事件还是普通事件选择不同的队列 */queue = (ngx_event_t **) (rev->accept ? &ngx_posted_accept_events : &ngx_posted_events);/* 将事件加入到延后运行队列中 */ngx_locked_post_event(rev, queue);} else {rev->handler(rev); /* 不须要延后,则马上处理事件 */}}/* 取出写事件 */wev = c->write;if ((revents & EPOLLOUT) && wev->active){/* 推断是否过期 */if (c->fd == -1 || wev->instance != instance)continue;....if (flags & NGX_POST_EVENTS) {/* 将写事件加入到延后处理队列 */ngx_locked_post_event(wev, &ngx_posted_events);} else {wev->handler(wev); /* 马上处理这个事件 */}}}ngx_mutex_unlock(ngx_posted_events_mutex);return NGX_OK;
}
转载于:https://www.cnblogs.com/hrhguanli/p/4589010.html
【Nginx】epoll事件驱动模块相关推荐
- nginx epoll详解
nginx epoll 事件模型 nginx做为一个异步高效的事件驱动型web服务器,在linux平台中当系统支持epoll时nginx默认采用epoll来高效的处理事件.nginx中使用ngx_ev ...
- Nginx 网络事件模型
网络收发与Nginx事件间的对应关系 请求建立TCP事件其实是发送的TCP报文到达了Nginx,所以其实是一个读事件,对于Nginx来说读取到了报文就是Accept建立连接的事件.TCP可读事件也 ...
- linux epoll事件模型详解
一.介绍 epoll是Linux(内核版本2.6及以上支持)下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率,因为它会复用文件 ...
- EPOLL 事件之 EPOLLRDHUP
在对系统问题进行排查时,我发现了一个奇怪的现象:明明是对方断开请求,系统却报告一个查询失败的错误,但从用户角度来看请求的结果正常返回,没有任何问题. 对这个现象深入分析后发现,这是一个基于 epoll ...
- EPOLL事件之EPOLLRDHUP
在对系统问题进行排查时,我发现了一个奇怪的现象:明明是对方断开连接,系统却报告一个查询失败的错误,但从用户角度来看请求的结果正常返回,没有任何问题. 对这个现象深入分析后发现,这是一个基于epoll的 ...
- epoll LT ET 区别 | Nginx epoll 原理 listend 用 LT
最近学 muduo 和 nginx 写网络库,总结一下 epoll 上遇到的一些问题和学习的笔记,主要是对 LT.ET 和平滑升级里的一些点理解一下.可以看作是上一次根据2.6 源码写的意识流(大白话 ...
- nginx陈旧事件(stale)的再理解
之前了解过nginx中有陈旧事件,也知道是通过instance的标记位来区分陈旧事件,但一直没从根本上理解整个过程的运行以及nginx如何解决.这次读了一些资料和源码,对陈旧事件有了本质的理解. 先说 ...
- nginx源码初读(8)--让烦恼从数据结构开始(ngx_event)
nginx中的事件模块是一个很重要的模块,但这里作为初读,我们只简单看一下ngx_event的数据结构,至于模块和机制,留作之后再分析. 下面是结构体ngx_event_t的代码: typedef s ...
- nginx ngx_event_t结构体详解
结构体 Event Handling | NGINX ngx_event_t:为添加到循环event事件使用的event事件结构体. typedef struct ngx_event_s ...
最新文章
- 数据库审计服务器性能要求,数据库审计技术指标资质要求-.docx
- 【NIO】阻塞与非阻塞
- ASP.NET MVC 5 入门教程 (2) 控制器Controller
- 【并查集】并查集的基本操作总结
- 11.【原创】chrom文件上传后,手动释放内存
- DS18B20 驱动编写
- docker挂载文件躺过的坑
- 筛选样本_早产预测准确性创新高!3种样本PK,首次利用脂质组学筛选出生物标志物...
- 凸透镜成像实验软件_凸透镜成像6道例题(含详答)
- centos7恢复mysql数据库_centos7 mysql数据库的安装与使用
- 指向API的函数指针定义方法
- SocksCapV2+Socks2HTTP
- smart原则_项目目标管理的 SMART 原则
- 基于算术优化算法的函数寻优算法
- 约分最简分式 (15 分)
- 配置MacTex的Tex Live Utility
- python 古典密码第一弹(凯撒密码,Playfair密码,维吉尼亚密码)
- Selenium模拟浏览器访问
- 2016计算机考研330分,考研330分什么概念_中国研究生招生信息网官方
- SpringBoot后台管理系统框架