Nginx Rtmp Learing 之基本數(shù)據(jù)結(jié)構(gòu)ngx_module_t

Nginx Rtmp Learing 之基本數(shù)據(jù)結(jié)構(gòu)ngx_module_t

1. ngx_module_t的基本結(jié)構(gòu)

對(duì)于開發(fā)一個(gè)模塊來(lái)說(shuō)辟汰,我們都需要定義一個(gè)ngx_module_t類型的變量來(lái)說(shuō)明這個(gè)模塊本身的信息贮竟,從某種意義上來(lái)說(shuō)失尖,這是這個(gè)模塊最重要的一個(gè)信息,它告訴了nginx這個(gè)模塊的一些信息纬朝,配置信息收叶,還有模塊上下文信息,都是通過(guò)這個(gè)結(jié)構(gòu)來(lái)告訴nginx系統(tǒng)的共苛,也就是加載模塊的上層代碼判没,都需要通過(guò)定義的這個(gè)結(jié)構(gòu),來(lái)獲取這些信息隅茎。

typedef struct ngx_module_s      ngx_module_t;
struct ngx_module_s {
    // 下面的幾個(gè)成員通常使用宏NGX_MODULE_V1填充

    // 每類(http/event)模塊各自的index澄峰, 初始化為-1
    ngx_uint_t            ctx_index;

    // 在ngx_modules數(shù)組里的唯一索引,main()里賦值
    // 使用計(jì)數(shù)器變量ngx_max_module
    ngx_uint_t            index;

    // 1.10辟犀,模塊的名字俏竞,標(biāo)識(shí)字符串,默認(rèn)是空指針
    // 由腳本生成ngx_module_names數(shù)組堂竟,然后在ngx_preinit_modules里填充
    // 動(dòng)態(tài)模塊在ngx_load_module里設(shè)置名字
    char                 *name;

    // 兩個(gè)保留字段胞此,1.9之前有4個(gè)
    ngx_uint_t            spare0;
    ngx_uint_t            spare1;

    // nginx.h:#define nginx_version      1010000
    ngx_uint_t            version;

    // 模塊的二進(jìn)制兼容性簽名,即NGX_MODULE_SIGNATURE
    const char           *signature;

    // 模塊不同含義不同,通常是函數(shù)指針表跃捣,是在配置解析的某個(gè)階段調(diào)用的函數(shù)
    // core模塊的ctx
    //typedef struct {
    //    ngx_str_t             name;
    //    void               *(*create_conf)(ngx_cycle_t *cycle);
    //    char               *(*init_conf)(ngx_cycle_t *cycle, void *conf);
    //} ngx_core_module_t;
    void                 *ctx;

    // 模塊支持的指令,數(shù)組形式夺蛇,最后用空對(duì)象表示結(jié)束
    ngx_command_t        *commands;

    // 模塊的類型標(biāo)識(shí)疚漆,相當(dāng)于RTTI,如CORE/HTTP/STRM/MAIL等
    ngx_uint_t            type;

    // 以下7個(gè)函數(shù)會(huì)在進(jìn)程的啟動(dòng)或結(jié)束階段被調(diào)用

    // init_master目前nginx不會(huì)調(diào)用
    ngx_int_t           (*init_master)(ngx_log_t *log);

    // 在ngx_init_cycle里被調(diào)用
    ngx_int_t           (*init_module)(ngx_cycle_t *cycle);

    // 在ngx_single_process_cycle/ngx_worker_process_init里調(diào)用
    ngx_int_t           (*init_process)(ngx_cycle_t *cycle);

    // init_thread目前nginx不會(huì)調(diào)用
    ngx_int_t           (*init_thread)(ngx_cycle_t *cycle);

    // exit_thread目前nginx不會(huì)調(diào)用
    void                (*exit_thread)(ngx_cycle_t *cycle);

    // 在ngx_worker_process_exit調(diào)用
    void                (*exit_process)(ngx_cycle_t *cycle);

    // 在ngx_master_process_exit(os/unix/ngx_process_cycle.c)里調(diào)用
    void                (*exit_master)(ngx_cycle_t *cycle);

    // 下面8個(gè)成員通常用用NGX_MODULE_V1_PADDING填充
    // 暫時(shí)無(wú)任何用處
    uintptr_t             spare_hook0;
    uintptr_t             spare_hook1;
    uintptr_t             spare_hook2;
    uintptr_t             spare_hook3;
    uintptr_t             spare_hook4;
    uintptr_t             spare_hook5;
    uintptr_t             spare_hook6;
    uintptr_t             spare_hook7;
};

2. ngx_modules數(shù)組

2.1 ngx_modules數(shù)組

ngx_modules數(shù)組是在執(zhí)行configure腳本后自動(dòng)生成的,在objs/ngx_modules.c文件中刁赦。該數(shù)組即當(dāng)前編譯版本中的所有Nginx模塊娶聘。

如果想讓nginx支持Rtmp的話,需要在執(zhí)行configure腳本時(shí)添加第三方庫(kù)nginx-rtmp-module

./configure --add-module=/path/to/nginx-rtmp-module

此時(shí)甚脉,objs/ngx_modules.c的內(nèi)容為:

ngx_module_t *ngx_modules[] = {
    &ngx_core_module,
    &ngx_errlog_module,
    &ngx_conf_module,
    &ngx_rtmp_module,
    &ngx_rtmp_core_module,
    &ngx_rtmp_cmd_module,
    &ngx_rtmp_billing_module,
    &ngx_rtmp_codec_module,
    &ngx_rtmp_access_module,
    &ngx_rtmp_record_module,
    &ngx_rtmp_live_module,
    &ngx_rtmp_hdl_module,
    &ngx_rtmp_hls_delay_module,
    &ngx_rtmp_hls_vod_module,
    &ngx_rtmp_hls_module,
    &ngx_rtmp_play_module,
    &ngx_rtmp_flv_module,
    &ngx_rtmp_mp4_module,
    &ngx_rtmp_netcall_module,
    &ngx_rtmp_relay_module,
    &ngx_rtmp_exec_module,
    &ngx_rtmp_auto_push_module,
    &ngx_rtmp_notify_module,
    &ngx_rtmp_listener_init_module,
    &ngx_rtmp_log_module,
    &ngx_rtmp_limit_module,
    &ngx_rtmp_dash_module,
    &ngx_openssl_module,
    &ngx_regex_module,
    &ngx_events_module,
    &ngx_event_core_module,
    &ngx_epoll_module,
    &ngx_http_module,
    &ngx_http_core_module,
    &ngx_http_log_module,
    &ngx_http_upstream_module,
    &ngx_http_static_module,
    &ngx_http_autoindex_module,
    &ngx_http_index_module,
    &ngx_http_auth_basic_module,
    &ngx_http_access_module,
    &ngx_http_limit_conn_module,
    &ngx_http_limit_req_module,
    &ngx_http_geo_module,
    &ngx_http_map_module,
    &ngx_http_split_clients_module,
    &ngx_http_referer_module,
    &ngx_http_rewrite_module,
    &ngx_http_proxy_module,
    &ngx_http_fastcgi_module,
    &ngx_http_uwsgi_module,
    &ngx_http_scgi_module,
    &ngx_http_memcached_module,
    &ngx_http_empty_gif_module,
    &ngx_http_browser_module,
    &ngx_http_upstream_hash_module,
    &ngx_http_upstream_ip_hash_module,
    &ngx_http_upstream_least_conn_module,
    &ngx_http_upstream_keepalive_module,
    &ngx_http_upstream_zone_module,
    &ngx_rtmp_http_hls_module,
    &ngx_rtmp_http_hdl_module,
    &ngx_rtmp_stat_module,
    &ngx_rtmp_control_module,
    &ngx_http_write_filter_module,
    &ngx_http_header_filter_module,
    &ngx_http_chunked_filter_module,
    &ngx_http_range_header_filter_module,
    &ngx_http_gzip_filter_module,
    &ngx_http_postpone_filter_module,
    &ngx_http_ssi_filter_module,
    &ngx_http_charset_filter_module,
    &ngx_http_userid_filter_module,
    &ngx_http_headers_filter_module,
    &ngx_http_copy_filter_module,
    &ngx_http_range_body_filter_module,
    &ngx_http_not_modified_filter_module,
    NULL
};

如上所述丸升,ngx_modules數(shù)組代表了當(dāng)前Nginx中的所有模塊。每一個(gè)Nginx模塊牺氨,即ngx_module_t類型的變量狡耻,其ctx變量一般為如下幾個(gè)類型之一:

    ngx_core_module_t
    ngx_event_module_t
    ngx_http_module_t
    ngx_mail_module_t

所以墩剖,可以對(duì)所有的Nginx模塊按其ctx類型進(jìn)行分類,當(dāng)然并不是所有的nginx模塊都有ctx成員夷狰,例如ngx_conf_module模塊的ctx成員為NULL,但可以認(rèn)為絕大部分模塊都屬于上述四類模塊之一岭皂。

每一類模塊下的所有模塊,由于其ctx結(jié)構(gòu)是一樣的沼头,因而在程序執(zhí)行邏輯上會(huì)有共同點(diǎn)爷绘。具體來(lái)說(shuō),我們可以遍歷ngx_modules數(shù)組成員进倍,判斷其屬于上述四類的哪一類模塊土至,再調(diào)用其對(duì)應(yīng)的ctx成員中的函數(shù)指針,這樣就會(huì)屏蔽掉具體的模塊名稱猾昆,抽象到框架的層面上陶因。

那么,如何判斷一個(gè)模塊屬于上述四類模塊中的哪一類呢毡庆?這就是模塊變量的type成員的作用了坑赡。

所有的ngx_core_module_t類型的模塊,其type成員為NGX_CORE_MODULE
所有的ngx_event_module_t類型的模塊么抗,其type成員為NGX_EVENT_MODULE
所有的ngx_http_module_t類型的模塊毅否,其type成員為NGX_HTTP_MODULE
所有的ngx_mail_module_t類型的模塊,其type成員為NGX_MAIL_MODULE

所以在遍歷ngx_modules數(shù)組時(shí)蝇刀,即可根據(jù)每一個(gè)數(shù)組成員的type成員螟加,來(lái)判斷該模塊屬于哪種類型的模塊,進(jìn)而執(zhí)行該模塊對(duì)應(yīng)的鉤子函數(shù)吞琐。

2.2 ngx_module_t的分層模塊結(jié)構(gòu)

Nginx 采用了分層模塊結(jié)構(gòu)設(shè)計(jì)捆探,頂層模塊由 Nginx 自身管理。比如站粟, 在 ngx_init_cycle 有一段代碼為:

ngx_cycle_t *
ngx_init_cycle(ngx_cycle_t *old_cycle)
{
    ngx_uint_t           i, n;

    // ...

    for (i = 0; cycle->modules[i]; i++) {
        if (cycle->modules[i]->type != NGX_CORE_MODULE) {
            continue;
        }

        module = cycle->modules[i]->ctx;

        if (module->create_conf) {
            rv = module->create_conf(cycle);
            if (rv == NULL) {
                ngx_destroy_pool(pool);
                return NULL;
            }
            cycle->conf_ctx[cycle->modules[i]->index] = rv;
        }
    }

    // ...

    for (i = 0; cycle->modules[i]; i++) {
        if (cycle->modules[i]->type != NGX_CORE_MODULE) {
            continue;
        }

        module = cycle->modules[i]->ctx;

        if (module->init_conf) {
            if (module->init_conf(cycle,
                                  cycle->conf_ctx[cycle->modules[i]->index])
                == NGX_CONF_ERROR)
            {
                environ = senv;
                ngx_destroy_cycle_pools(&conf);
                return NULL;
            }
        }
    }

    // ...

    return NULL;
}

類型為 NGX_CORE_MODULE 的模塊的 create_confinit_conf 會(huì)被調(diào)用黍图。 類型為 NGX_CORE_MODULE 的摸塊即屬于 Nginx 中的頂層模塊。 頂層模塊除負(fù)責(zé)像日志打印奴烙、配置解析等核心業(yè)務(wù)外助被,也需要管理二級(jí)模塊的接入。 實(shí)際上切诀,上層模塊負(fù)責(zé)下層模塊的接入揩环,這是一種很自然的設(shè)計(jì)。 假如幅虑,我們自己在 Nginx 中擴(kuò)展了二級(jí)模塊丰滑,而由于業(yè)務(wù)復(fù)雜,我們需要進(jìn)一步進(jìn)行模塊劃分倒庵。 而新劃分出的模塊則屬于三級(jí)模塊褒墨,那這三級(jí)模塊的接入不由我們自己定義的二級(jí)模塊接入又該由誰(shuí)負(fù)責(zé)呢炫刷?

rtmp模塊的類型為 NGX_RTMP_MODULE,Nginx中與rtmp相關(guān)的模塊有: ngx_rtmp_module, ngx_rtmp_core_module, ngx_rmtp_***_module貌亭。 其中 ngx_rtmp_module 屬于頂層模塊柬唯,但它負(fù)責(zé)二級(jí)事件模塊的接入; ngx_rtmp_core_module 是核心的事件模塊圃庭,它負(fù)責(zé)server,application配置文件的解析和管理锄奢、事件的掛載、初始化listen等剧腻; ngx_rtmp_**_module 是nginx下的其它所有的rtmp模塊拘央。 我們來(lái)ngx_rtmp_module這個(gè)頂層模塊的實(shí)現(xiàn):

2.3 ngx_rtmp_module(ngx_rtmp.c文件)

2.3.1 ngx_rtmp_module的定義

ngx_module_t  ngx_rtmp_module = {
    NGX_MODULE_V1,
    &ngx_rtmp_module_ctx,                  /* module context */
    ngx_rtmp_commands,                     /* module directives */
    NGX_CORE_MODULE,                       /* module type */
    NULL,                                  /* init master */
    NULL,                                  /* init module */
    ngx_rtmp_init_process,                 /* init process */
    NULL,                                  /* init thread */
    NULL,                                  /* exit thread */
    NULL,                                  /* exit process */
    NULL,                                  /* exit master */
    NGX_MODULE_V1_PADDING
};

2.2.2 ngx_rtmp_module的上下文(ngx_rtmp_module_ctx)

// 核心模塊的ctx結(jié)構(gòu),比較簡(jiǎn)單书在,只有創(chuàng)建和初始化配置結(jié)構(gòu)函數(shù) .
// create_conf函數(shù)返回的是void*指針

static ngx_core_module_t  ngx_rtmp_module_ctx = {
    ngx_string("rtmp"),             /*name*/
    NULL,                           /*create_conf*/
    NULL                            /*init_conf*/
};

2.2.3 模塊配置指令(ngx_rtmp_commands)

// 指令結(jié)構(gòu)體灰伟,用于定義nginx指令
static ngx_command_t  ngx_rtmp_commands[] = {

    { ngx_string("rtmp"),
      NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
      ngx_rtmp_block,
      0,
      0,
      NULL },

      ngx_null_command
};

看這個(gè)定義,基本能看出來(lái)一些信息儒旬。例如栏账,我們是定義了一個(gè)配置指令叫rtmp,不接受任何參數(shù)栈源。

接下來(lái)看下ngx_command_t的定義挡爵,位于src/core/ngx_conf_file.h中。

struct ngx_command_s {
    ngx_str_t             name;
    ngx_uint_t            type;
    char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
    ngx_uint_t            conf;
    ngx_uint_t            offset;
    void                 *post;
};

name: 配置指令的名稱甚垦。

type: 該配置的類型茶鹃,其實(shí)更準(zhǔn)確一點(diǎn)說(shuō),是該配置指令屬性的集合艰亮。

set: 這是一個(gè)函數(shù)指針闭翩,當(dāng)nginx在解析配置的時(shí)候,如果遇到這個(gè)配置指令迄埃,將會(huì)把讀取到的值傳遞給這個(gè)函數(shù)進(jìn)行分解處理疗韵。因?yàn)榫唧w每個(gè)配置指令的值如何處理,只有定義這個(gè)配置指令的人是最清楚的侄非。來(lái)看一下這個(gè)函數(shù)指針要求的函數(shù)原型蕉汪。

char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

先看該函數(shù)的返回值,處理成功時(shí)彩库,返回NGX_OK,否則返回NGX_CONF_ERROR或者是一個(gè)自定義的錯(cuò)誤信息的字符串先蒋。

再看一下這個(gè)函數(shù)被調(diào)用的時(shí)候骇钦,傳入的三個(gè)參數(shù)。

  • cf: 該參數(shù)里面保存從配置文件讀取到的原始字符串以及相關(guān)的一些信息竞漾。特別注意的是這個(gè)參數(shù)的args字段是一個(gè)ngx_str_t類型的數(shù)組眯搭,該數(shù)組的首個(gè)元素是這個(gè)配置指令本身窥翩,第二個(gè)元素是指令的第一個(gè)參數(shù),第三個(gè)元素是第二個(gè)參數(shù)鳞仙,依次類推寇蚊。
  • cmd: 這個(gè)配置指令對(duì)應(yīng)的ngx_command_t結(jié)構(gòu)。
  • conf: 就是定義的存儲(chǔ)這個(gè)配置值的結(jié)構(gòu)體棍好。用戶在處理的時(shí)候可以使用類型轉(zhuǎn)換仗岸,轉(zhuǎn)換成自己知道的類型,再進(jìn)行字段的賦值借笙。
// 空指令扒怖,用于在指令數(shù)組的最后當(dāng)做哨兵,結(jié)束數(shù)組业稼,避免指定長(zhǎng)度盗痒,類似NULL的作用
#define ngx_null_command  { ngx_null_string, 0, NULL, 0, 0, NULL }

2.3 ngx_rtmp_block配置解析函數(shù)

這個(gè)函數(shù)可以理解為整個(gè)ngx_rtmp_module的入口函數(shù):

// 解析rtmp{}配置塊,里面有server{}/application{}等
// 只有出現(xiàn)這個(gè)指令才會(huì)在conf_ctx里創(chuàng)建rtmp配置低散,避免內(nèi)存浪費(fèi)
// 統(tǒng)計(jì)rtmp模塊的數(shù)量,設(shè)置rtmp模塊的ctx_index俯邓,即rtmp模塊自己的序號(hào)
// 調(diào)用每個(gè)rtmp模塊的create_xxx_conf函數(shù),創(chuàng)建配置結(jié)構(gòu)體
// 初始化rtmp處理引擎的階段數(shù)組熔号,調(diào)用ngx_array_init
// 整理所有的rtmp handler模塊稽鞭,填入引擎數(shù)組
// 調(diào)用ngx_create_listening添加到cycle的監(jiān)聽端口數(shù)組,只是添加跨嘉,沒(méi)有其他動(dòng)作
// 設(shè)置有連接發(fā)生時(shí)的回調(diào)函數(shù)ngx_rtmp_init_connection

static char *
ngx_rtmp_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    char                        *rv;
    ngx_uint_t                   m, mi, s;
    ngx_conf_t                   pcf;
    ngx_rtmp_module_t           *module;
    ngx_rtmp_conf_ctx_t         *ctx;
    ngx_rtmp_core_srv_conf_t    *cscf, **cscfp;
    ngx_rtmp_core_main_conf_t   *cmcf;

    /* the main rtmp context */

    // ngx_rtmp_conf_ctx_t里有三個(gè)void*數(shù)組川慌,存儲(chǔ)三個(gè)層次的模塊配置
    // in ngx_rtmp.h
    //
    // typedef struct {
    //     void        **main_conf;
    //     void        **srv_conf;
    //     void        **loc_conf;
    // } ngx_rtmp_conf_ctx_t;
    
    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_conf_ctx_t));
    if (ctx == NULL) {
        return NGX_CONF_ERROR;
    }

    *(ngx_rtmp_conf_ctx_t **) conf = ctx;

    /* count the number of the rtmp modules and set up their indices */
    // 統(tǒng)計(jì)rtmp模塊的數(shù)量
    // 設(shè)置rtmp模塊的ctx_index,即rtmp模塊自己的序號(hào)
    
    ngx_rtmp_max_module = 0;
    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
            continue;
        }

        ngx_modules[m]->ctx_index = ngx_rtmp_max_module++;
    }


    /* the rtmp main_conf context, it is the same in the all rtmp contexts */
    // main配置數(shù)組祠乃,所有rtmp模塊只有一個(gè)
    ctx->main_conf = ngx_pcalloc(cf->pool,
                                 sizeof(void *) * ngx_rtmp_max_module);
    if (ctx->main_conf == NULL) {
        return NGX_CONF_ERROR;
    }


    /*
     * the rtmp null srv_conf context, it is used to merge
     * the server{}s' srv_conf's
     */
    
    // srv配置數(shù)組梦重,在rtmp main層次存儲(chǔ)server基本的配置,用于合并
    // 本身并無(wú)實(shí)際意義
    ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_rtmp_max_module);
    if (ctx->srv_conf == NULL) {
        return NGX_CONF_ERROR;
    }


    /*
     * the rtmp null app_conf context, it is used to merge
     * the server{}s' app_conf's
     */
     
    // location配置數(shù)組亮瓷,在rtmp main層次存儲(chǔ)location基本的配置琴拧,用于合并
    // 本身并無(wú)實(shí)際意

    ctx->app_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_rtmp_max_module);
    if (ctx->app_conf == NULL) {
        return NGX_CONF_ERROR;
    }

    /*
     * create the main_conf's, the null srv_conf's, and the null app_conf's
     * of the all rtmp modules
     */
     
    // 調(diào)用每個(gè)rtmp模塊的create_xxx_conf函數(shù),創(chuàng)建配置結(jié)構(gòu)體

    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
            continue;
        }

        module = ngx_modules[m]->ctx;
        mi = ngx_modules[m]->ctx_index;

         // 創(chuàng)建每個(gè)模塊的main_conf
        if (module->create_main_conf) {
            ctx->main_conf[mi] = module->create_main_conf(cf);
            if (ctx->main_conf[mi] == NULL) {
                return NGX_CONF_ERROR;
            }
        }
        
        // 創(chuàng)建每個(gè)模塊的srv_conf
        if (module->create_srv_conf) {
            ctx->srv_conf[mi] = module->create_srv_conf(cf);
            if (ctx->srv_conf[mi] == NULL) {
                return NGX_CONF_ERROR;
            }
        }

         // 創(chuàng)建每個(gè)模塊的loc_conf
        if (module->create_app_conf) {
            ctx->app_conf[mi] = module->create_app_conf(cf);
            if (ctx->app_conf[mi] == NULL) {
                return NGX_CONF_ERROR;
            }
        }
    }

    // 初始的解析環(huán)境已經(jīng)準(zhǔn)備好嘱支,下面開始解析rtmp{}配置

    // 暫存當(dāng)前的解析上下文
    // cf是函數(shù)入口傳遞來(lái)的上下文
    
    pcf = *cf;
    
    // 設(shè)置事件模塊的新解析上下文
    // 即ngx_http_conf_ctx_t結(jié)構(gòu)體
    
    cf->ctx = ctx;

    // 解析之前蚓胸,調(diào)用preconfiguration,可以添加變量定義
    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
            continue;
        }

        module = ngx_modules[m]->ctx;

        if (module->preconfiguration) {
            if (module->preconfiguration(cf) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }
    }

    /* parse inside the rtmp{} block */
    // 設(shè)置解析的類型等信息
    // NGX_HTTP_MODULE用來(lái)檢查是否是http模塊除师,防止用錯(cuò)了指令
    
    cf->module_type = NGX_RTMP_MODULE;
    cf->cmd_type = NGX_RTMP_MAIN_CONF;
    
    // 遞歸解析rtmp模塊
    rv = ngx_conf_parse(cf, NULL);

    if (rv != NGX_CONF_OK) {
        *cf = pcf;
        return rv;
    }


    /* init rtmp{} main_conf's, merge the server{}s' srv_conf's */

    // 解析完畢沛膳,檢查rtmp{}里定義的server{}塊
    cmcf = ctx->main_conf[ngx_rtmp_core_module.ctx_index];
    
    // 所有server{}定義的配置都保存在core module main conf的serevrs數(shù)組里
    cscfp = cmcf->servers.elts;

    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
            continue;
        }

        module = ngx_modules[m]->ctx;
        mi = ngx_modules[m]->ctx_index;

        /* init rtmp{} main_conf's */

        cf->ctx = ctx;

        // 初始化main配置
        if (module->init_main_conf) {
            rv = module->init_main_conf(cf, ctx->main_conf[mi]);
            if (rv != NGX_CONF_OK) {
                *cf = pcf;
                return rv;
            }
        }

        for (s = 0; s < cmcf->servers.nelts; s++) {

            /* merge the server{}s' srv_conf's */

            cf->ctx = cscfp[s]->ctx;
                
            // 合并srv配置
            if (module->merge_srv_conf) {
                rv = module->merge_srv_conf(cf,
                                            ctx->srv_conf[mi],
                                            cscfp[s]->ctx->srv_conf[mi]);
                if (rv != NGX_CONF_OK) {
                    *cf = pcf;
                    return rv;
                }
            }

            if (module->merge_app_conf) {

                /* merge the server{}'s app_conf */

                /*ctx->app_conf = cscfp[s]->ctx->loc_conf;*/

                rv = module->merge_app_conf(cf,
                                            ctx->app_conf[mi],
                                            cscfp[s]->ctx->app_conf[mi]);
                if (rv != NGX_CONF_OK) {
                    *cf = pcf;
                    return rv;
                }

                /* merge the applications{}' app_conf's */

                cscf = cscfp[s]->ctx->srv_conf[ngx_rtmp_core_module.ctx_index];

                rv = ngx_rtmp_merge_applications(cf, &cscf->applications,
                                            cscfp[s]->ctx->app_conf,
                                            module, mi);
                if (rv != NGX_CONF_OK) {
                    *cf = pcf;
                    return rv;
                }
            }

        }
    }


    if (ngx_rtmp_init_events(cf, cmcf) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
            continue;
        }

        module = ngx_modules[m]->ctx;

        // 執(zhí)行每個(gè)rtmp模塊的postconfiguration函數(shù)指針
        //** 通常是向phase數(shù)組里添加handler**
        if (module->postconfiguration) {
            if (module->postconfiguration(cf) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }
    }

    // 恢復(fù)之前保存的解析上下文
    *cf = pcf;

    if (ngx_rtmp_init_event_handlers(cf, cmcf) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

     /* optimize the lists of ports, addresses and server names */

    // 類似stream模塊,對(duì)已經(jīng)整理好的監(jiān)聽端口數(shù)組排序
    // 調(diào)用ngx_create_listening添加到cycle的監(jiān)聽端口數(shù)組汛聚,只是添加锹安,沒(méi)有其他動(dòng)作
    // 設(shè)置有連接發(fā)生時(shí)的回調(diào)函數(shù)ngx_rtmp_init_connection
    return ngx_rtmp_optimize_servers(cf, cmcf, &cmcf->ports);
}

參考文章:

https://github.com/chronolaw/annotated_nginx
http://tengine.taobao.org/book/
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子叹哭,更是在濱河造成了極大的恐慌忍宋,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,946評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件风罩,死亡現(xiàn)場(chǎng)離奇詭異糠排,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)超升,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門入宦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人廓俭,你說(shuō)我怎么就攤上這事云石。” “怎么了研乒?”我有些...
    開封第一講書人閱讀 169,716評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵汹忠,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我雹熬,道長(zhǎng)宽菜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,222評(píng)論 1 300
  • 正文 為了忘掉前任竿报,我火速辦了婚禮铅乡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘烈菌。我一直安慰自己阵幸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,223評(píng)論 6 398
  • 文/花漫 我一把揭開白布芽世。 她就那樣靜靜地躺著挚赊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪济瓢。 梳的紋絲不亂的頭發(fā)上荠割,一...
    開封第一講書人閱讀 52,807評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音旺矾,去河邊找鬼蔑鹦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛箕宙,可吹牛的內(nèi)容都是我干的嚎朽。 我是一名探鬼主播,決...
    沈念sama閱讀 41,235評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼柬帕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼哟忍!你這毒婦竟也來(lái)了室囊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,189評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤魁索,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后盼铁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粗蔚,經(jīng)...
    沈念sama閱讀 46,712評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,775評(píng)論 3 343
  • 正文 我和宋清朗相戀三年饶火,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鹏控。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,926評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肤寝,死狀恐怖当辐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鲤看,我是刑警寧澤缘揪,帶...
    沈念sama閱讀 36,580評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站义桂,受9級(jí)特大地震影響找筝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜慷吊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,259評(píng)論 3 336
  • 文/蒙蒙 一袖裕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧溉瓶,春花似錦急鳄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,750評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至胞锰,卻和暖如春灾锯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嗅榕。 一陣腳步聲響...
    開封第一講書人閱讀 33,867評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工顺饮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人凌那。 一個(gè)月前我還...
    沈念sama閱讀 49,368評(píng)論 3 379
  • 正文 我出身青樓兼雄,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親帽蝶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赦肋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,930評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容