资讯详情

Nginx配置文件解析之一

现在针对nginx源码分析的blog有很多文章,我以前读过很多,每个人的分析都很好。太多重复的内容不会写,主要是为了分析代码和查阅我blog在这个过程中,我发现了一些模糊的地方或一些细节需要讨论,给出了我自己的理解和观点,希望与你交流和学习。

使用的nginx版本是nginx-1.0.6.我第一次看到的代码是0.7.62.新版本在功能和稳定性方面做了很多工作。

在分析的时候,我尽量简单明了,不太重要的地方,具体可以看代码。详细介绍相对复杂或晦涩的地方。

首先,我们从配置文件开始,以下分析是基于网民nginx在大致熟悉配置文件结构的前提下,可以很好地理解代码。

有必要在原始代码目录中提醒:ngx_modules这种结构找不到它的定义和初始化。如果你想看到它,你必须执行它configure,make,在原始代码目录下会出现一个objs文件夹,三个文件夹,ngx_auto_config.h,ngx_auto_headers.h,ngx_modules.c,需要在建source insight它还包含在项目中,这有助于我们掌握整个代码结构。呵呵,有趣的是,nginx的configure文件是作者手写的,管理代码工程的方法很多,有时间值得学习。

1.ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle);

配置文件的解析相关的处理主要在ngx_init_cycle函数被调用。在这种情况下,让我们先谈谈ngx_init_cycle函数吧。

它需要一个参数类型ngx_cycle_t *,返回值也是一个ngx_cycle_t*,同时,我们注意到参数被命名为old_cycle,那么这个函数的作用是什么呢?很明显是由old得到一个new。其中ngx_cycle_t结构保存了一些全球配置和信息。函数的具体作用将是reconfig(重读配置文件)可以理解为old_cycle是当前正在使用的配置信息,当配置文件做了某些修改之后,ngx_init_cycle通过old_cycle有些数据,对new_cycle经过进一步的配置分析,进行一些设置,你可以得到一个new cycle。

2.char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)

当我们使用sourceinsight检查函数的调用情况时,会发现调用函数的地方很多。其实入口点在ngx_init_cycle中对ngx_conf_parse调用,后面所有的调用都可以看作是递归调用。为什么会这样?原因在于nginx它是在阅读配置信息时分析和执行相关处理。具体来说,它是读一行,执行一行。一行的定义是指以分号或{和}结束的一行。例如,我们分析它http {}httpblock在处理过程中,我们会再次遇到server {},自然调用server block的处理。。。。以此类推!。

读取配置文件主要是函数ngx_conf_read_token中间,这个函数每次都会NGX_CONF_BUFFER(即4KB)读取内存的配置信息buf中,然后对buf分析。除了这个函数,函数的返回值主要是通过不同的处理来处理的。你可以仔细阅读它的返回值的含义,意义非常明确!

我们可以通过上述操作获得配置指令,每个字符串都保存在一个字符串数组中(即cf->args),代码显然反映了这一点。之后,我们调用ngx_conf_handler处理当前获得的行配置的函数。让我们从总体上谈谈ngx_conf_handler该函数的工作原理:它通过系统中的所有模块配置,找到特定的模块,匹配特定的命令,然后执行。让我们来谈谈。

nginx所有模块都将被分类和管理。当然,每个模块都被分成集合。同一模块下的指令也被分类(如属于哪种模块、配置正确等),因此每次调用ngx_conf_parse例如:

conf.module_type= NGX_CORE_MODULE; conf.cmd_type = NGX_MAIN_CONF;

我们将分析我们得到的指令core module在类型中搜索,并找到module中类型为main conf的指令。

在进入重点之前,我们先看一个地方,那就是cf->handler它是怎么处理的?是这样的,nginx一般处理函数ngx_conf_handler主要是针对cf->args使用的字符串数组,如一些配置,如types,charset_map,这不是一个简单的字符串数组,指令的参数可能会放在{}中,因此通用的分析和处理函数不适用。我们注册cf->handler,我们可以对以下{}中的参数进行常规配置。

我们进入到ngx_conf_handler函数中,看看它的工作机理。

3. static ngx_int_t

ngx_conf_handler(ngx_conf_t *cf,ngx_int_t last)

参数last是ngx_conf_read_token分析的返回结果。强调的是,cf->args我们需要的参数已经保存了。

下一步的处理分为四步:

(1) 模块匹配

代码显示得很明显,它首先会根据您指定的类型找到特定的模块。

(2) command匹配

找到匹配的模块之后会遍历该模块下的command数组需要找到它command信息。如果字面上匹配,也要进行command类型配置检查,如此时类型不匹配,nginx向你报告。

(3) 匹配参数的数量

对个数有严格要求的主要检查command,对于任何数量(即NGX_CONF_ANY)的command,直接处理。

关于参数个数,nginx定义了一些宏,如NGX_CONF_TAKEx(x代表1、2、3等,表示可配置一个、两个、三个参数。。),还有像1MORE,2MORE,意思也很清楚。注意有个数限制command,最多可配置8个,即NGX_CONF_MAX_ARGS,这你自己的module注意,我在这方面遭受了损失。。。

(4) 执行command(即set函数)。

嗯,前面的检查工作完成后,就要真正执行相关操作,生成module配置信息。

这里涉及command找出它对后面的理解是非常重要的。Let’s go!

NGX_DIRECT_CONF,NGX_MAIN_CONF,NGX_HTTP_MAIN_CONF,NGX_HTTP_SRV_CONF,NGX_HTTP_LOC_CONF等

其中NGX_DIRECT_CONF一般是在http块等以外的配置, NGX_HTTP_MAIN_CONF直接配置http块中的,NGX_HTTP_SRV_CONF配置在server块中,NGX_HTTP_LOC_CONF配置在location中等等。

我们来看cf->ctx这个成员的类型是void *,在这里你大概会猜到它的用处,一定是在不同的条件下转来转去!

在ngx_init_cycle我们发现了最初cf->ctx的值由cycle->conf_ctx赋值得到,cycle->conf_ctx是一个void ****类型。(-_-!)

在ngx_init_cycle有这样一句关键的句子:

cycle->conf_ctx =ngx_pcalloc(pool, ngx_max_module * sizeof(void *));

所以,这里ngx_max_module是系统中的一切module的总数,conf_ctx在这句话中,个人module占据一个位置(一个指针),但是每个位置指向什么呢?反正是个void *,一般来说,它只指向某些模块的配置结构,但对于某些模块,我们需要通过n层指针(例如void ****)这种设计是为了逻辑分层和模块划分。

绕了一圈,我们发现这些指针数组的最终成员赋值将在这里完成:

这里有三种情况:

(1) NGX_DIRECT_CONF

对于游离{}以外的配置,一般属于ngx_core_conf_t配置内容,在ngx_init_cycle时间是对的NGX_CORE_MODULE模块类型初始化(模块需要init根据配置信息,函数),set函数会做配置结构内中成员的赋值。

(2) NGX_MAIN_CONF

这样的配置包括event,http等等,他们没有init函数,因此需要实际的空间分配set函数完成后,就有了:

conf =&(((void **) cf->ctx)[ngx_modules[i]->index]); //取指针地址

rv =cmd->set(cf, cmd, conf); // 函数中赋值指针

set中conf参数是二重指针,之后就有了ngx_http_block中的语句:

ctx =ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));

*(ngx_http_conf_ctx_t **) conf = ctx;

(3)其他

其实这里的其他主要是一些server和location的类型的command,这些command大量集中http在相关配置中。

我们先来看ngx_http_conf_ctx_t结构:

typedefstruct {

void**main_conf;

void**srv_conf;

void**loc_conf;

}ngx_http_conf_ctx_t;

这里有一件事需要解释,就像http在模块下,有一些所谓的子模块,这些子模块基本上是都是http中server或者location中的一些配置。这些配置通过模块中ctx_index,以数组的形式,将他们的配置结构的指针保存在srv_conf或loc_conf中,这就是他们的类型为什么会是void **。

看下面的行代码:

cmd->conf是cf->ctx成员的位移,这里的处理就是把该位置的成员当成一个指针来处理,而实际上,它是一个二级指针,即子模块配置的指针的数组!

confp =*(void **) ((char *) cf->ctx + cmd->conf);

conf = confp[ngx_modules[i]->ctx_index]; // 拿到配置结构

rv =cmd->set(cf, cmd, conf); // 做处理

最后说明一下,开始提到的那个void ****类型成员,使用这种类型的原因我们可以在ngx_events_block函数中找到答案。

(未完待续)

标签: takex竹中光电传感器astakex竹中传感器us系列takex竹中传感器ustakex竹中传感器f11cr

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台