设为首页 加入收藏

TOP

Nginx情景分析之配置文件解析(一)
2014-11-24 13:02:41 来源: 作者: 【 】 浏览:1
Tags:Nginx 情景 分析 配置 文件 解析

现在针对nginx源码分析的blog和文章已经很多了,之前我也看过不少,大家的分析都很不错。在这里,我不想写太多重复的内容,只是针对在我分析代码和查阅blog的过程中,发现的一些比较晦涩或者某些细节有待展开讨论的地方,给出我的自己理解和看法,希望跟大家交流和学习。标题为情景分析,目的是向许多情景分析经典(如linux内核情景分析)致敬,力求做到深入深刻。


使用的nginx版本是nginx-1.0.6,我最开始看的代码是0.7.62,新的版本在功能和稳定性上做了很多的工作。


在分析的时候,我尽量简单明了,不太重要的地方一带而过,具体地大家可以去读代码。相对复杂或者晦涩的地方,将详细展开。希望大家认同我的一个观点:我容易看得懂的地方,大家也不难看懂;而我认为比较难懂的地方,通常情况下大家读起来也不会太省力!


首先我们从配置文件开始,下面的分析是建立在网友对nginx的配置文件结构有大概熟悉为前提,这样才可以很好的理解代码。


这里有必要提醒一点:原始代码中ngx_modules你找不到它的定义和初始化,要看到它,你必须执行configure,make,在原来的代码目录下会出现一个objs文件夹,里面的3个文件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。好了,init 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的处理。。。以此类推!。


配置指令我们通过上面的操作就可以拿到了,以空格分开的各个字符串被保存在一个字符串数组里(即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的指令。



好了解析来我们进入到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中已经保存了我们需要的各个参数。


接下来的处理分4步走:


(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中等等。



接下来是考验你c语言指针功底的时候了,呵呵!


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


在ngx_init_cycle中我们发现最初cf->ctx的值由cycle->conf_ctx赋值得到,cycle->conf_ctx是一个void ****类型(-_-!最开始的时候我曾经很好奇,这样的指针到底会用来做什么?),它的作用我们很快揭晓。


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


cycle->con

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Linux 2.4.0 内核bootsect.S文件.. 下一篇Linux禁用字符闪烁的方法

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·Sphinx : 高性能SQL (2025-12-24 10:18:11)
·Pandas 性能优化 - (2025-12-24 10:18:08)
·MySQL 索引 - 菜鸟教 (2025-12-24 10:18:06)
·Shell 基本运算符 - (2025-12-24 09:52:56)
·Shell 函数 | 菜鸟教 (2025-12-24 09:52:54)