zoukankan      html  css  js  c++  java
  • 【Nginx】核心模块ngx_events_module

    核心模块ngx_events_module是一个专门用于管理事件模块的模块。

    它的实现非常easy。以下是该模块的定义:

    ngx_module_t  ngx_events_module = {
        NGX_MODULE_V1,
        &ngx_events_module_ctx,                /* module context */
        ngx_events_commands,                   /* module directives */
        NGX_CORE_MODULE,                       /* module type */
        NULL,                                  /* init master */
        NULL,                                  /* init module */
        NULL,                                  /* init process */
        NULL,                                  /* init thread */
        NULL,                                  /* exit thread */
        NULL,                                  /* exit process */
        NULL,                                  /* exit master */
        NGX_MODULE_V1_PADDING
    }; 


    解析配置项的ngx_events_commands结构体数组定义例如以下:
    // 定义了怎样处理感兴趣的配置项
    static ngx_command_t  ngx_events_commands[] = {
        {
            ngx_string("events"), /* 仅仅对events块配置项感兴趣 */
            NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
            ngx_events_block,     /* 解析配置项的函数 */
            0,
            0,
            NULL
        },
        ngx_null_command
    }; 


    能够看到,核心模块ngx_events_module仅仅对配置文件里的“events”块配置项感兴趣。并用ngx_events_block方法进行解析。ngx_events_block在后面解说。

    通用接口ngx_events_module_ctx定义例如以下:
    static ngx_core_module_t  ngx_events_module_ctx = {
        ngx_string("events"),
        NULL,                  /* create_conf */
        ngx_event_init_conf    /* init_conf */
    }; 


    ngx_event_init_conf函数内貌似没有做什么特别的工作。所以我们能够忽略它。相当于该接口仅仅是定义了该模块的名字而已。

    这是由于ngx_events_module并不解析配置项參数,仅仅是在events块配置项出现后调用各个事件模块去解析events内的配置项,所以它自己并不须要实现create_conf方法和init_conf方法。


    怎样管理事件模块配置项
    事件模块的通用接口是ngx_event_module_t,定义例如以下:
    typedef struct {
        ngx_str_t              *name;   // 事件模块名字
        // 解析配置项之前调用,创建存储配置项參数的结构体
        void                 *(*create_conf)(ngx_cycle_t *cycle);
        // 解析完配置项后的回调函数
        char                 *(*init_conf)(ngx_cycle_t *cycle, void *conf);
        // 每一个事件模块须要实现的10个抽象方法
        ngx_event_actions_t     actions;
    } ngx_event_module_t;   // 事件模块通用接口
    


    每一个事件模块使用init_conf成员函数创建存储配置项的结构体并返回指向这个结构体的指针。

    这个指针放在了ngx_events_module核心模块创建的指针数组中,例如以下图所看到的:



    这样。每个进程的核心结构体ngx_cycle_t就行和全部模块的存储配置项的结构体相关联了。那么每个事件模块调用create_conf方法所返回的指针又是如何放进核心模块的数组中的呢?还是上面提到的ngx_events_block方法。以下就来解说ngx_events_block。此函数的流程图例如以下:


    该方法的代码例如以下,已经被我简化了。凝视中的序号相应上面的每一步:
    static char *
    ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
    {
        char                 *rv;
        void               ***ctx;
        ngx_uint_t            i;
        ngx_conf_t            pcf;
        ngx_event_module_t   *m;
        ngx_event_max_module = 0;
        for (i = 0; ngx_modules[i]; i++)
        {
            if (ngx_modules[i]->type != NGX_EVENT_MODULE)
                continue;
            /* 1.初始化全部事件模块的ctx_index成员
             * 该成员表明了该模块在同样类型模块中的顺序。这会决定以后载入各事件模块的顺序
             */
            ngx_modules[i]->ctx_index = ngx_event_max_module++;
        }
        /* 分配一个存放指针的空间 */
        ctx = ngx_pcalloc(cf->pool, sizeof(void *));
        /* 2.ngx_event_max_module等于事件模块个数 */
        *ctx = ngx_pcalloc(cf->pool, ngx_event_max_module * sizeof(void *));
        *(void **) conf = ctx;  /* conf指向存储參数的结构体 */
        for (i = 0; ngx_modules[i]; i++)
        {
            if (ngx_modules[i]->type != NGX_EVENT_MODULE)
                continue;
            m = ngx_modules[i]->ctx;    /* 得到事件模块的通用接口 */
            if (m->create_conf)
                /* 3.调用全部事件模块的通用接口ngx_event_module_t中的create_conf方法 */
                (*ctx)[ngx_modules[i]->ctx_index] = m->create_conf(cf->cycle);
        }
        pcf = *cf;
        cf->ctx = ctx;
        cf->module_type = NGX_EVENT_MODULE;
        cf->cmd_type = NGX_EVENT_CONF;
        /* 4.针对全部事件模块调用各自的解析配置文件的方法
         * 当发现对应配置项后。就调用模块中ngx_command_t数组中的方法
         */
        rv = ngx_conf_parse(cf, NULL);  /* cf中保存有读到的配置项參数 */
        *cf = pcf;
        for (i = 0; ngx_modules[i]; i++)
        {
            if (ngx_modules[i]->type != NGX_EVENT_MODULE)
                continue;
            m = ngx_modules[i]->ctx;
            if (m->init_conf)
                /* 5.解析完配置项后,调用每一个模块的init_conf方法对配置參数进行整合 */
                rv = m->init_conf(cf->cycle, (*ctx)[ngx_modules[i]->ctx_index]);
        }
        return NGX_CONF_OK;
    } 


    以上代码用ngx_pcalloc函数分配了两块内存,第一个ngx_pcalloc创建一个可以存放指针的空间,相当于图9-2上面那个数组中的第四个单元;而第二个ngx_pcalloc则创建了一个指针数组,存放指针的数量等于事件模块的数量,相应图9-2以下的那个数组。此函数运行完成时,全部事件模块都在核心模块ngx_events_module的管理下成功读取配置项。

    以上就是管理事件的核心模块ngx_events_module。

    事件驱动机制很多其它的工作是在ngx_event_core_module模块中完毕,下次再写。


    參考:
    《深入理解Nginx》 P300-P305.
  • 相关阅读:
    《C++ Primer》学习笔记第2章 变量和基本类型
    Java学习笔记类的继承与多态特性
    Java的冒泡排序问题
    新起点,分享,进步
    MVC2中Area的路由注册实现
    了解一下new关键字实现阻断继承的原理
    利用Bing API开发的搜索工具(MVC+WCF)
    ASP.NET MVC中错误处理方式
    const和readonly内部区别
    WCF中校验参数的实现方式(一)
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5321887.html
Copyright © 2011-2022 走看看