Web服务器在面对高并发的情况下,网络的IO一般选择IO复用,像apache选择的Select/poll。Nginx在linux 2.6后选择Epoll做网路IO,提高了WEB服务的并发能力。

在本章,我们将看看NGINX如何使用epoll。

首先,我们看一下数据结构图:

1、从结构图中,我们先看第一部分,NGINX拿到socket标示符,绑定本地地址,监听socket标示符信息,由于NGINX支持多server,支持各个server使用不同的端口、不同的协议族。如此需要多个socket句柄来支持,NGINX利用ngx_listening_t这个数据结构来保存打开的socket信息并且放置在一个数组里面。这个过程是在初始化cycle中完成的。

2、关于socket句柄,我们区分两类,一类是上一部分说的服务端申请的socket,这一部分socket处理和客户端连接的情况,如果有新的连接进来,将会产生关于这一批socket的事件;第二类,是连接建立后,服务端accept客户端的socket句柄,针对这个句柄,服务端做读和写的操作。

我们再看一下下图绘制的一个处理流程。

我们再通过代码来看看整个过程

分析配置文件,申请socket fd

2、处理事件模块的初始化

static ngx_int_t
ngx_event_process_init(ngx_cycle_t *cycle)
{
....... //对所有NGX_EVENT_MODULE模块执行module->actions.init
for (m = ; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_EVENT_MODULE) {
continue;
} if (ngx_modules[m]->ctx_index != ecf->use) {
continue;
} module = ngx_modules[m]->ctx; if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) {
/* fatal */
exit();
} break;
} ...... cycle->connections =
ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log);
if (cycle->connections == NULL) {
return NGX_ERROR;
} c = cycle->connections; cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,
cycle->log);
if (cycle->read_events == NULL) {
return NGX_ERROR;
} rev = cycle->read_events;
for (i = ; i < cycle->connection_n; i++) {
rev[i].closed = ;
rev[i].instance = ;
#if (NGX_THREADS)
rev[i].lock = &c[i].lock;
rev[i].own_lock = &c[i].lock;
#endif
} cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,
cycle->log);
if (cycle->write_events == NULL) {
return NGX_ERROR;
} wev = cycle->write_events;
for (i = ; i < cycle->connection_n; i++) {
wev[i].closed = ;
#if (NGX_THREADS)
wev[i].lock = &c[i].lock;
wev[i].own_lock = &c[i].lock;
#endif
} i = cycle->connection_n;
next = NULL; do {
i--; c[i].data = next;
c[i].read = &cycle->read_events[i];
c[i].write = &cycle->write_events[i];
c[i].fd = (ngx_socket_t) -; next = &c[i]; #if (NGX_THREADS)
c[i].lock = ;
#endif
} while (i); cycle->free_connections = next;
cycle->free_connection_n = cycle->connection_n; /* for each listening socket */ ls = cycle->listening.elts;
for (i = ; i < cycle->listening.nelts; i++) { //获取空余连接,将服务端申请的每个socket fd占用一个连接,
c = ngx_get_connection(ls[i].fd, cycle->log); ......
rev->handler = ngx_event_accept; if (ngx_use_accept_mutex) {
continue;
} if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
if (ngx_add_conn(c) == NGX_ERROR) {
return NGX_ERROR;
} } else {
//如果使用epoll模块,则在epoll上注册读事件,操作类型是EPOLL_CTL_ADD,也就是关注服务端申请的socket fd是否有新连接申请
if (ngx_add_event(rev, NGX_READ_EVENT, ) == NGX_ERROR) {
return NGX_ERROR;
}
} } return NGX_OK;
}

3、  EPOLL在发现新事件后,会查找处理该事件的方法,实际上先查找对应的连接,该连接指针是如下方式,利用epoll_event结构体成员data的ptr指针可以用来存储用户的连接信息,我们在看看后面是怎么处理的

static ngx_int_t
ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
{
.......
//epoll_event结构体成员data的ptr指针可以用来存储用户的指针信息,这里用来存储连接信息,其中事件的instance标识主要用来显示事件是否过期 ee.events = events | (uint32_t) flags;
ee.data.ptr = (void *) ((uintptr_t) c | ev->instance); //把instance加到ee的末尾(由于内存对齐,末尾一般为0) ……. if (epoll_ctl(ep, op, c->fd, &ee) == -) {
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
"epoll_ctl(%d, %d) failed", op, c->fd);
return NGX_ERROR;
}
....... return NGX_OK;
}

4、

static void
ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
{
...... ngx_worker_process_init(cycle, worker); ...... for ( ;; ) { ......
ngx_process_events_and_timers(cycle);
......
}
}

5、

void
ngx_process_events_and_timers(ngx_cycle_t *cycle)
{
......
(void) ngx_process_events(cycle, timer, flags);
...... }

Nginx源码研究三:Epoll在NGINX中的使用的更多相关文章

  1. Chrome自带恐龙小游戏的源码研究(三)

    在上一篇<Chrome自带恐龙小游戏的源码研究(二)>中实现了云朵的绘制和移动,这一篇主要研究如何让游戏实现昼夜交替. 昼夜交替的效果主要是通过样式来完成,但改变样式的时机则由脚本控制. ...

  2. Nginx源码研究七:nginx的location指令分析

    在nginx的配置文件nginx.conf中,我们在配置server的时候,会配置一下location指令,这个location指令是提供给用户来配置对于符合指令的http请求,采用该指令内部的处理方 ...

  3. Nginx源码研究一:NGINX模块启动

    Nginx 是一个轻量级,但是高性能的 HTTP 和 代理 服务器,也是一个 IMAP/POP3/SMTP代理服务器. 它的第一个版本0.1.0是由俄罗斯的工程师Igor Sysoev与2004年10 ...

  4. Nginx源码研究六:NGINX的配置文件分析

    上一篇写到nginx的各个模块的配置信息的存储结构,大体描述了对配置信息的配置项生成,定制,初始化过程.这里重点研究实现定制的过程,所谓实现定制,这里指的是,nginx系统提供使用者定义nginx的配 ...

  5. [nginx] nginx源码分析--proxy模式下nginx的自动重定向auto_redirect

    描述 我们配置了一个proxy模式下的nginx, upstream backend-test { server ; } server { listen ; location = /nginx/hww ...

  6. Nginx源码研究二:NGINX的事件处理概论

    NGINX作为服务端的应用程序,在客户端发出数据后,服务端在做着这样一些处理,数据先会经过网卡,网卡会和操作系统做交互,经过操作系统的协议栈处理,再和不同的应用程序交互. 在这里面涉及两个概念,一个是 ...

  7. Nginx源码研究五:NGINX的配置信息管理

    配置信息是nginx系统重要的组成部分,配置信息的使用,实际上包含两层,一层是用户针对参数定义了值,例如下面nginx参数文件中的 keepalive_timeout 65,还有一部分是用户没有定义值 ...

  8. Nginx源码研究八:nginx监听socket实现流程

    前面描述了nginx系统分析nginx的配置文件,初始化模块相关参数的过程,这里利用nginx监听socket的实现过程,做一次完整的回顾 1.首先,nginx启动的main函数中,会先初始化cycl ...

  9. Nginx源码研究四:NGINX的内存管理

    关于nginx的内存使用,我们先看代码,下面是nginx_cycle.c中对全局数据结构cycle的初始化过程 pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, ...

随机推荐

  1. Java---常用基础面试知识点

    综合网上的一点资源,给大家整理了一些Java常用的基础面试知识点,希望能帮助到刚开始学习或正在学习的学员. 1.抽象 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方 ...

  2. ubuntu14.04下交叉编译器的安装

    今天打算换个工作环境,在ubuntu下装交叉编译器,可谓一波三折.最后总算是装好了. 首先参照一下这位仁兄的博客http://blog.csdn.net/silleyj/article/details ...

  3. Android Studio开发环境部署

    Step0:背景,那些年-- Step1:安装JDK Step2:安装Android Studio 其他问题1:安装Android Studio之前没有先安装JDK 其他问题2:No JVM inst ...

  4. 关于C#中Thread.Join()的一点理解

    原文地址:http://www.cnblogs.com/slikyn/articles/1525940.html 今天是第一次在C#中接触Thread,自己研究了一下其中Thread.Join()这个 ...

  5. 铁通、长宽网络支付时“签名失败”问题分析及解决方案  [88222001]验证签名异常:FAIL[20131101100002-142]

    原文地址:http://bbs.tenpay.com/forum.php?mod=viewthread&tid=13723&highlight=%CC%FA%CD%A8 如果你的是铁通 ...

  6. jQuery(二)

    jQuery学完了!好用! 1.用定时器做的jquery里面的animate效果 <!DOCTYPE html> <html lang="en"> < ...

  7. unity3D基础学习 通过判断鼠标点击的是否是目标物体,物体旋转,滑动滚轮缩放拉近视角

    贴代码: 摄像机的拉近视角代码: public Transform target;     public float minFov = 15f;     public float maxFov = 7 ...

  8. SKTransition类

    继承自 NSObject 符合 NSObject(NSObject) 框架  /System/Library/Frameworks/SpriteKit.framework 可用性 可用于iOS 7.0 ...

  9. 【经典面试题】实现平方根函数sqrt

    本文将从一道经典的面试题说起:实现平方根函数,不得调用其它库函数. 函数原型声明例如以下: double Sqrt(double A); 二分法 二分法的概念 求,等价于求方程的非负根(解).求解方程 ...

  10. 在Mac中安装.Net Core的开发环境

    在mac中部署dotnet core开发环境,我的MacOS版本号为OSX EI Capitan 10.11.6 1.安装brew homebrew官网推荐的安装命令如下: /usr/bin/ruby ...