目录

一、Nginx的配置文件nginx.conf

二、数据结构逻辑关系图

三、相关数据结构

1. ngx_cycle_s的conf_ctx和modules

2. ngx_module_s的index和commands

3. ngx_command_s 命令集的结构

四、核心模块的定义

1. 核心模块在nginx.c的文件头部

2. 核心模块的配置结构ngx_core_conf_t

五、具体解析流程

1. 创建核心模块配置文件数据结构ngx_core_conf_t

2. 创建一个临时的ngx_conf_s结构

3. 调用解析配置函数ngx_conf_param和ngx_conf_parse

4. 配置文件核心解析函数ngx_conf_parse

5. 命令token解析 ngx_conf_read_token

Nginx源码中比较重要的一块就是配置文件的解析。一般是解析/usr/local/nginx/conf/nginx.conf文件中的配置信息。

前一篇文章,我们介绍了Nginx的模块化。Nginx的功能模块都是通过cycle->modules 模块进行管理的。而每个模块都会有自己的配置文件。

一、Nginx的配置文件nginx.conf
Nginx的配置文件每一行就是一条命令。
最外层的为核心模块的配置参数(类型:NGX_CORE_MODULE);内部嵌套的为各个子模块的配置。
events {} 为事件模块(类型:NGX_EVENT_MODULE)
http {} 为HTTP模块 (类型:NGX_HTTP_MODULE)
http模块内还会嵌套多层
多层嵌套会在后续的event模块中介绍。这里只介绍最顶层的core模块的解析。
配置的层次结构如下图:

Main CODE
          /                     \

Events                     Http

/            \                        /            \

epoll            kqueue                 Server          Server

/             \                   \

Location     Location      Location

#user  nobody;
worker_processes  1;#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;#pid        logs/nginx.pid;events {worker_connections  1024;
}http {include       mime.types;default_type  application/octet-stream;#log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '#                  '$status $body_bytes_sent "$http_referer" '#                  '"$http_user_agent" "$http_x_forwarded_for"';#access_log  logs/access.log  main;sendfile        on;#tcp_nopush     on;#keepalive_timeout  0;keepalive_timeout  65;#gzip  on;server {listen       80;server_name  localhost;#charset koi8-r;#access_log  logs/host.access.log  main;location / {root   html;index  index.html index.htm;}#error_page  404              /404.html;# redirect server error pages to the static page /50x.html#error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}# proxy the PHP scripts to Apache listening on 127.0.0.1:80##location ~ \.php$ {#    proxy_pass   http://127.0.0.1;#}# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000##location ~ \.php$ {#    root           html;#    fastcgi_pass   127.0.0.1:9000;#    fastcgi_index  index.php;#    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;#    include        fastcgi_params;#}# deny access to .htaccess files, if Apache's document root# concurs with nginx's one##location ~ /\.ht {#    deny  all;#}}# another virtual host using mix of IP-, name-, and port-based configuration##server {#    listen       8000;#    listen       somename:8080;#    server_name  somename  alias  another.alias;#    location / {#        root   html;#        index  index.html index.htm;#    }#}# HTTPS server##server {#    listen       443 ssl;#    server_name  localhost;#    ssl_certificate      cert.pem;#    ssl_certificate_key  cert.key;#    ssl_session_cache    shared:SSL:1m;#    ssl_session_timeout  5m;#    ssl_ciphers  HIGH:!aNULL:!MD5;#    ssl_prefer_server_ciphers  on;#    location / {#        root   html;#        index  index.html index.htm;#    }#}}

二、数据结构逻辑关系图

三、相关数据结构
1. ngx_cycle_s的conf_ctx和modules
cycle->conf_ctx :配置文件上下文数组。每个模块的配置文件数据结构的指针地址都会按照模块的index索引放置在cycle->conf_ctx数组中。

cycle->modules:模块数组。模块也会按照模块的索引index放在cycle->modules数组上。具体可以参考《Nginx源码分析 - 主流程篇 - 模块的初始化 》中ngx_cycle_modules方法。

/*** Nginx全局变量cycle*/
struct ngx_cycle_s {void                  ****conf_ctx; /* 配置文件 上下文的数组,每个模块的配置信息*/ngx_pool_t               *pool;    /* 内存池地址 */...ngx_module_t            **modules;    /* 模块数组 */ngx_uint_t                modules_n;  /* 模块个数 */ngx_uint_t                modules_used;    /* unsigned  modules_used:1; */...
};

2. ngx_module_s的index和commands


  • index:是模块的索引值。

  • commands:模块支持的命令集。主要用于将配置信息设置到每个模块的配置文件数据结构上(例如核心模块的ngx_core_conf_t)。

/*** 业务模块数据结构*/
struct ngx_module_s {ngx_uint_t            ctx_index;ngx_uint_t            index; /* 模块的唯一标识符号 */char                 *name;  /* 模块名称 */...void                 *ctx;   /* 模块上下文 */ngx_command_t        *commands; /* 模块支持的命令集 */ngx_uint_t            type;    /* 模块类型 */...
};

3. ngx_command_s 命令集的结构


set:为回调函数。最终设置值的时候,都会调用set的回调函数。

/*** 模块支持的命令集结构*/
struct ngx_command_s {ngx_str_t             name; /* 命令名称 */ngx_uint_t            type; /* 命令类别 */char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); /* set回调函数 */ngx_uint_t            conf;ngx_uint_t            offset; /* 偏移量,命令长度 */void                 *post; /* 支持的回调方法;大多数情况为NULL*/
};

四、核心模块的定义
从上面的数据结构我们知道,每个模块都必须定义一个模块的数据结构ngx_module_s,主要用于管理每个模块的具体信息;每个模块也会定义一个ngx_command_t数组,主要用于存放需要解析的命令集的规则。

而最终的配置文件信息,由于每个模块的配置结构不同,所以在cycle->conf_ctx只保存每个模块配置文件数据结构的指针地址。

1. 核心模块在nginx.c的文件头部
核心模块

/*** 定义核心配置模块命令集ngx_command_t结构*/
static ngx_command_t  ngx_core_commands[] = {{ ngx_string("daemon"), /* 命令名称 */NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG, /* 类型 */ngx_conf_set_flag_slot, /* 回调方法 */0,offsetof(ngx_core_conf_t, daemon), /* 偏移量;使用这个偏移量后,可以参考 ngx_core_module_create_conf*/NULL },{ ngx_string("master_process"),NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG,ngx_conf_set_flag_slot,0,offsetof(ngx_core_conf_t, master),NULL },{ ngx_string("timer_resolution"),NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,ngx_conf_set_msec_slot,0,offsetof(ngx_core_conf_t, timer_resolution),NULL },{ ngx_string("pid"),NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,ngx_conf_set_str_slot,0,offsetof(ngx_core_conf_t, pid),NULL },{ ngx_string("lock_file"),NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,ngx_conf_set_str_slot,0,offsetof(ngx_core_conf_t, lock_file),NULL },{ ngx_string("worker_processes"),NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,ngx_set_worker_processes,0,0,NULL },{ ngx_string("debug_points"),NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,ngx_conf_set_enum_slot,0,offsetof(ngx_core_conf_t, debug_points),&ngx_debug_points },{ ngx_string("user"),NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE12,ngx_set_user,0,0,NULL },{ ngx_string("worker_priority"),NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,ngx_set_priority,0,0,NULL },{ ngx_string("worker_cpu_affinity"),NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_1MORE,ngx_set_cpu_affinity,0,0,NULL },{ ngx_string("worker_rlimit_nofile"),NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,ngx_conf_set_num_slot,0,offsetof(ngx_core_conf_t, rlimit_nofile),NULL },{ ngx_string("worker_rlimit_core"),NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,ngx_conf_set_off_slot,0,offsetof(ngx_core_conf_t, rlimit_core),NULL },{ ngx_string("working_directory"),NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,ngx_conf_set_str_slot,0,offsetof(ngx_core_conf_t, working_directory),NULL },{ ngx_string("env"),NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,ngx_set_env,0,0,NULL },{ ngx_string("load_module"),NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,ngx_load_module,0,0,NULL },ngx_null_command
};/*** 核心模块上下文* ngx_core_module_create_conf 核心模块创建配置文件* ngx_core_module_init_conf 核心模块初始化配置文件*/
static ngx_core_module_t  ngx_core_module_ctx = {ngx_string("core"),ngx_core_module_create_conf,ngx_core_module_init_conf
};/*** 核心模块*/
ngx_module_t  ngx_core_module = {NGX_MODULE_V1,&ngx_core_module_ctx,                  /* module context */ngx_core_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_core_module 核心模块。主要管理核心模块的信息。
ngx_core_module_ctx 核心模块的上下文。每个模块的上下文都不同,所以模块结构中只给了一个void的指针类型,可以指向不同的数据结构。核心模块的ngx_core_module_ctx主要定义了ngx_core_module_create_conf和ngx_core_module_init_conf回调函数(创建和初始化配置文件)
ngx_core_commands 核心模块定义的命令集。当nginx.conf中的命令被拆简后,会通过这个命令集,逐个将核心模块的命令赋值到核心模块的配置文件数据结构上。
2. 核心模块的配置结构ngx_core_conf_t
核心模块的配置结构ngx_core_conf_t。ngx_core_conf_t的指针地址会按照模块的index索引,放在cycle->conf_ctx数组中。

ngx_core_conf_t结构的创建和初始化。ngx_core_module_create_conf和ngx_core_module_init_conf方法。

/*** 核心配置文件信息* 对应nginx.conf的* #user  nobody;worker_processes  1;#error_log  logs/error.log;#error_log  logs/error.log  notice;#error_log  logs/error.log  info;#pid        logs/nginx.pid;*/
typedef struct {ngx_flag_t                daemon;ngx_flag_t                master;ngx_msec_t                timer_resolution;ngx_int_t                 worker_processes;ngx_int_t                 debug_points;ngx_int_t                 rlimit_nofile;off_t                     rlimit_core;int                       priority;ngx_uint_t                cpu_affinity_auto;ngx_uint_t                cpu_affinity_n;ngx_cpuset_t             *cpu_affinity;char                     *username;ngx_uid_t                 user;ngx_gid_t                 group;ngx_str_t                 working_directory;ngx_str_t                 lock_file;ngx_str_t                 pid;ngx_str_t                 oldpid;ngx_array_t               env;char                    **environment;
} ngx_core_conf_t;

五、具体解析流程
我们这边主要讲解核心模块配置信息的解析。通过对核心模块的解析流程的理解,能更好的帮助你了解整个Nginx的模块管理和配置管理的流程。HTTP等模块的配置文件解析会更加复杂一些,但是基本原理是一致的。

1. 创建核心模块配置文件数据结构ngx_core_conf_t
ngx_init_cycle全局变量的初始化中会初始化Nginx的核心模块的配置信息。核心模块的配置参数在nginx.conf文件中最顶层的一些参数配置。

下面这段代码我们可以看到,遍历模块数组,如果是核心模块,则获取核心模块的上下文cycle->modules[i]->ctx,核心模块上下文是一个自定义的数据结构ngx_core_module_ctx,里面包含了配置文件创建的回调函数ngx_core_module_create_conf

PS:这边只是针对性NGX_CORE_MODULE进行创建配置文件和初始化配置文件。

    /** 核心模块的配置文件创建* 配置创建调用nginx.c 中的 ngx_core_module_create_conf* 以及其他核心模块的init_conf,例如:ngx_event_core_module_ctx中的ngx_event_core_create_conf* */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; //配置文件复制}}

2. 创建一个临时的ngx_conf_s结构


ngx_conf_s主要定义了需要解析的配置文件,需要解析的模块类型以及命令集类型的信息。辅助解析配置文件。

    /* 解析配置文件 */ngx_memzero(&conf, sizeof(ngx_conf_t));/* STUB: init array ? */conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t));if (conf.args == NULL) {ngx_destroy_pool(pool);return NULL;}/* 创建一个临时的内存池,后面会清空掉;conf也主要用于解析配置文件的临时变量 */conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);if (conf.temp_pool == NULL) {ngx_destroy_pool(pool);return NULL;}conf.ctx = cycle->conf_ctx;conf.cycle = cycle;conf.pool = pool;conf.log = log;conf.module_type = NGX_CORE_MODULE; /* 配置文件模块类型 */conf.cmd_type = NGX_MAIN_CONF; /* 命令集类型 */

3. 调用解析配置函数ngx_conf_param和ngx_conf_parse
ngx_conf_param:主要解析命令行中的核心模块配置参数,例如:nginx -t -c /usr/local/nginx/conf/nginx.conf
ngx_conf_parse:主要解析配置文件/usr/local/nginx/conf/nginx.conf 信息
ngx_conf_param:最终也是调用ngx_conf_parse

    /* 解析命令行中的配置参数;例如:nginx -t -c /usr/local/nginx/conf/nginx.conf */if (ngx_conf_param(&conf) != NGX_CONF_OK) {environ = senv;ngx_destroy_cycle_pools(&conf);return NULL;}/* 解析配置文件/usr/local/nginx/conf/nginx.conf 信息 */if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {environ = senv;ngx_destroy_cycle_pools(&conf);return NULL;}

4. 配置文件核心解析函数ngx_conf_parse
ngx_conf_parse解析命令中的配置信息和文件中的配置信息.

主要工作是按行读取配置文件,并且解析成配置token数组,并将token数组进行模块commend命令集匹配和设置。

其中比较重要的函数:

ngx_conf_read_token 按行读取配置文件,并将命令解析成token数组cf->args;
ngx_conf_handler 将命令token数组与模块命令集匹配并设置到模块配置文件数据结构上。

/*** 解析配置信息核心函数* 包含:解析命令中的配置信息和文件中的配置信息*/
char *
ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
{.../* 打开配置文件: /usr/local/nginx/conf/nginx.conf */if (filename) {/* open configuration file */fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); //只读方式打开文件if (fd == NGX_INVALID_FILE) {ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,ngx_open_file_n " \"%s\" failed",filename->data);return NGX_CONF_ERROR;}prev = cf->conf_file;cf->conf_file = &conf_file;if (ngx_fd_info(fd, &cf->conf_file->file.info) == NGX_FILE_ERROR) {ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,ngx_fd_info_n " \"%s\" failed", filename->data);}/* 配置文件buf,默认大小4096 */cf->conf_file->buffer = &buf;buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log);if (buf.start == NULL) {goto failed;}buf.pos = buf.start;buf.last = buf.start;buf.end = buf.last + NGX_CONF_BUFFER;buf.temporary = 1;/* 读取配置文件数据,保存到cf->conf_file中 */cf->conf_file->file.fd = fd;cf->conf_file->file.name.len = filename->len;cf->conf_file->file.name.data = filename->data;cf->conf_file->file.offset = 0;cf->conf_file->file.log = cf->log;cf->conf_file->line = 1;type = parse_file;...} else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {/*** 解析块:events {  worker_connections  1024; }*/type = parse_block;} else {type = parse_param;}for ( ;; ) {/* 将配置信息解析成 token;仅仅是将配置文件的数据解析成一个个的单词,按行解析 */rc = ngx_conf_read_token(cf);/** ngx_conf_read_token() may return**    NGX_ERROR             there is error 解析失败*    NGX_OK                the token terminated by ";" was found  遇到结尾符号;,则表示解析成功*    NGX_CONF_BLOCK_START  the token terminated by "{" was found  遇到{模块配置开始标识*    NGX_CONF_BLOCK_DONE   the "}" was found  遇到模块}结束标识*    NGX_CONF_FILE_DONE    the configuration file is done 遇到文件解析完毕*/if (rc == NGX_ERROR) {goto done;}/* 一个模块解析结束,则跳到done模块代码 */if (rc == NGX_CONF_BLOCK_DONE) {if (type != parse_block) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");goto failed;}goto done;}/* 一个模块解析结束,则跳到done模块代码 */if (rc == NGX_CONF_FILE_DONE) {if (type == parse_block) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"unexpected end of file, expecting \"}\"");goto failed;}goto done;}if (rc == NGX_CONF_BLOCK_START) {if (type == parse_param) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"block directives are not supported ""in -g option");goto failed;}}/* rc == NGX_OK || rc == NGX_CONF_BLOCK_START *//* 当遇到 NGX_CONF_BLOCK_START 和  NGX_OK*/if (cf->handler) {/** the custom handler, i.e., that is used in the http's* "types { ... }" directive*/if (rc == NGX_CONF_BLOCK_START) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\"");goto failed;}rv = (*cf->handler)(cf, NULL, cf->handler_conf);if (rv == NGX_CONF_OK) {continue;}if (rv == NGX_CONF_ERROR) {goto failed;}ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv);goto failed;}/* 配置文件处理;将配置文件设置到模块上 */rc = ngx_conf_handler(cf, rc);if (rc == NGX_ERROR) {goto failed;}}failed:
...return NGX_CONF_OK;
}

5. 命令token解析 ngx_conf_read_token
ngx_conf_read_token 主要是将配置文件分解成逐个的单词数组。例如配置文件中遇到“空格”则为分隔符,“;”为结束符。

每一个数组,就是一条配置命令语句。数组会放置到cf->args数组上。

nginx.conf配置文件如下:

user  nfsnobody nfsnobody;
worker_processes 8;
error_log  /usr/local/nginx-1.4.7/nginx_error.log  crit;
pid        /usr/local/nginx-1.4.7/nginx.pid;
#Specifies the value for maximum file descriptors that can be opened by this process.
worker_rlimit_nofile 65535;
events
{
use epoll;
worker_connections 65535;}

解析成下面的格式:

#分解成逐个单词数组:
user
nfsnobody
nfsnobodyworker_processes
8error_log
/usr/local/nginx-1.4.7/nginx_error.log
critpid
/usr/local/nginx-1.4.7/nginx.pidworker_rlimit_nofile
65535events

具体逻辑实现:

/*** 读取配置信息* 把每次分析的值放到cf->args这个数组里面  碰到{} ; 返回* 例如配置文件如下:* user  nfsnobody nfsnobody;* worker_processes 8;* error_log  /usr/local/nginx-1.4.7/nginx_error.log  crit;* pid        /usr/local/nginx-1.4.7/nginx.pid;* #Specifies the value for maximum file descriptors that can be opened by this process.* worker_rlimit_nofile 65535;* events* {* use epoll;* worker_connections 65535;}** 分解成逐个单词:* user* nfsnobody* nfsnobody* worker_processes* 8* error_log* /usr/local/nginx-1.4.7/nginx_error.log* crit* pid* /usr/local/nginx-1.4.7/nginx.pid* worker_rlimit_nofile* 65535* events**/
static ngx_int_t
ngx_conf_read_token(ngx_conf_t *cf)
{u_char      *start, ch, *src, *dst;off_t        file_size;size_t       len;ssize_t      n, size;ngx_uint_t   found, need_space, last_space, sharp_comment, variable;ngx_uint_t   quoted, s_quoted, d_quoted, start_line;ngx_str_t   *word;ngx_buf_t   *b, *dump;found = 0; //表示找到一个 tokenneed_space = 0;last_space = 1; //标志位,表示上一个字符为token分隔符sharp_comment = 0; //注释 #符号variable = 0; //变量符号 $quoted = 0;   //标志位,表示上一个字符为反斜杠s_quoted = 0; //标志位,表示已扫描一个双引号,期待另一个双引号d_quoted = 0; //标志位,表示已扫描一个单引号,期待另一个单引号cf->args->nelts = 0;b = cf->conf_file->buffer; //buffer 每次4096dump = cf->conf_file->dump;start = b->pos;start_line = cf->conf_file->line;file_size = ngx_file_size(&cf->conf_file->file.info);for ( ;; ) {/* buf中的数据已经处理完毕,则需要判断是否文件读取完了,如果没有读取完,则继续解析配置文件 */if (b->pos >= b->last) {/* 文件已经读取完毕,返回NGX_CONF_FILE_DONE */if (cf->conf_file->file.offset >= file_size) {if (cf->args->nelts > 0 || !last_space) {if (cf->conf_file->file.fd == NGX_INVALID_FILE) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"unexpected end of parameter, ""expecting \";\"");return NGX_ERROR;}ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"unexpected end of file, ""expecting \";\" or \"}\"");return NGX_ERROR;}return NGX_CONF_FILE_DONE;}/* buf中已经使用的长度  */len = b->pos - start;/* 如果len=4096 则表明buf全部读取满了;如果读取了4096个字符,还是没有发现"和'的标示符号,则认为读取失败,参数太长了 */if (len == NGX_CONF_BUFFER) {cf->conf_file->line = start_line;if (d_quoted) {ch = '"';} else if (s_quoted) {ch = '\'';} else {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"too long parameter \"%*s...\" started",10, start);return NGX_ERROR;}ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"too long parameter, probably ""missing terminating \"%c\" character", ch);return NGX_ERROR;}/* 将数据移动到buf的头部 */if (len) {ngx_memmove(b->start, start, len);}/* 如果buf有空闲,则继续读取文件中的数据到buf中 */size = (ssize_t) (file_size - cf->conf_file->file.offset);if (size > b->end - (b->start + len)) {size = b->end - (b->start + len);}n = ngx_read_file(&cf->conf_file->file, b->start + len, size,cf->conf_file->file.offset);if (n == NGX_ERROR) {return NGX_ERROR;}if (n != size) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,ngx_read_file_n " returned ""only %z bytes instead of %z",n, size);return NGX_ERROR;}/* 设置b->pos和b->last的位置,并重新设置start的位置 */b->pos = b->start + len;b->last = b->pos + n;start = b->start;if (dump) {dump->last = ngx_cpymem(dump->last, b->pos, size);}}/* ch字符用于读取配置文件信息 */ch = *b->pos++;/* 如果遇到换行符号 \n */if (ch == LF) {cf->conf_file->line++;/* 判断改行是否是注释 如果遇到\n结尾,并且是注释,则设置sharp_comment = 0;当sharp_comment=1 则注释字符不处理*/if (sharp_comment) {sharp_comment = 0;}}/* 注释,则直接跳过 */if (sharp_comment) {continue;}/* 如果为反引号,则设置反引号标识,并且不对该字符进行解析   */if (quoted) {quoted = 0;continue;}/* 上一个字符为单引号或者双引号,期待一个分隔符   */if (need_space) {...}}
}

设值到模块配置文件数据结构上 ngx_conf_handler

ngx_conf_handler方法主要是将拿到的token数组cf->args,按照模块的命令集cycle->modules[i]->commands 设置值。(后面解析event和http头部核心模块的时候,会用到)

通过模块的index索引值,拿到cycle->ctx 模块配置文件数据结构。
通过rv = cmd->set(cf, cmd, conf),调用命令集中定义的设值值的回调方法。
这边会根据模块类型,将配置信息逐个解析到相应的模块上。

/*** 配置文件处理* cycle->modules*/
static ngx_int_t
ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
{char           *rv;void           *conf, **confp;ngx_uint_t      i, found;ngx_str_t      *name;ngx_command_t  *cmd;name = cf->args->elts;found = 0;/* 循环配置模块 */for (i = 0; cf->cycle->modules[i]; i++) {cmd = cf->cycle->modules[i]->commands;if (cmd == NULL) {continue;}for ( /* void */ ; cmd->name.len; cmd++) {if (name->len != cmd->name.len) {continue;}/* 检查配置名称和token的第一个元素的名称是否一致,如果不一致,则说明命令不一样 */if (ngx_strcmp(name->data, cmd->name.data) != 0) {continue;}found = 1;if (cf->cycle->modules[i]->type != NGX_CONF_MODULE&& cf->cycle->modules[i]->type != cf->module_type){continue;}.../* is the directive's argument count right ? */if (!(cmd->type & NGX_CONF_ANY)) {...}/* set up the directive's configuration context */conf = NULL;/* 设置配置文件的值  设置配置项对外面的配置信息; */if (cmd->type & NGX_DIRECT_CONF) {/* ngx_core_module; */conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index];} else if (cmd->type & NGX_MAIN_CONF) {conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);} else if (cf->ctx) {confp = *(void **) ((char *) cf->ctx + cmd->conf);if (confp) {conf = confp[cf->cycle->modules[i]->ctx_index];}}/*** 配置文件设置值;* conf为配置的指针地址;* cmd为命令结构;* conf为配置指针地址 一般情况下 conf为模块自定义的配置文件数据结构地址**/rv = cmd->set(cf, cmd, conf);if (rv == NGX_CONF_OK) {return NGX_OK;}if (rv == NGX_CONF_ERROR) {return NGX_ERROR;}ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"\"%s\" directive %s", name->data, rv);return NGX_ERROR;}}...return NGX_ERROR;
}

nginx_conf_file.c文件中定义了多种配置文件值设值的方法:

char *ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_str_array_slot(ngx_conf_t *cf, ngx_command_t *cmd,void *conf);
char *ngx_conf_set_keyval_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_off_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_sec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_bufs_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

调用核心模块的配置

通过核心模块ngx_core_module的索引index值,就可以得到核心配置的数据结构 ngx_core_conf_t

    /* 获取核心配置文件的数据结构 ngx_core_conf_t */ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);

参考文章:

1.https://initphp.blog.csdn.net/article/details/51911189

2.

Nginx源码分析 - 主流程篇 - 解析配置文件(13)相关推荐

  1. Nginx 源码分析-- 模块module 解析执行 nginx.conf 配置文件流程分析 一

    搭建nginx服务器时,主要的配置文件 nginx.conf 是部署和维护服务器人员经常要使用到的文件, 里面进行了许多服务器参数的设置.那么nginx 以模块 module为骨架的设计下是如何运用模 ...

  2. Nginx 源码分析

    1.工程 ngx_conf_file.c ngx_connection.c ngx_cycle.c ngx_file.h ngx_module.c ngx_open_file_cache.h ngx_ ...

  3. Lua源码分析 - 虚拟机篇 - 语义解析之Opcode执行(18)

    目录 一.虚拟机篇 - 指令执行状态机luaV_execute 二.虚拟机篇 - 状态机的具体实现原理 一.虚拟机篇 - 指令执行状态机luaV_execute 在<Lua源码分析 - 主流程篇 ...

  4. nginx源码分析(5)——监听socket初始化

    在nginx源码分析(4)中,看到了nginx的事件模型,但其中没有介绍监听socket的初始化.而对于web server来说,需要通过监听socket来监听客户端的连接等.本篇将会具体介绍这方面的 ...

  5. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  6. Nginx源码分析:核心数据结构ngx_cycle_t与内存池概述

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> 核心数据结构与内存池概述 在Nginx中的核心数据结构就是ngx_cycle_t结构,在初始 ...

  7. Nginx源码分析:master/worker工作流程概述

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> Nginx的master与worker工作模式 在生成环境中的Nginx启动模式基本都是以m ...

  8. Nginx源码分析:启动流程

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> nginx简介 Nginx的作为服务端软件,表现的主要特点是更快.高扩展.高可靠性.低内存消 ...

  9. MyBatis 源码分析 - 映射文件解析过程

    1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...

  10. Nginx源码分析之 upstream指令

    #Nginx 源码分析 upstream指令 想要的解决问题: 1:upstream存储结构 2:动态 upstream 流程(proxy_pass跟随变量或者域名) 最简单的配置文件 http {u ...

最新文章

  1. 无法识别的配置节appsettings_人脸识别门禁考勤系统安装使用注意事项
  2. Python学习之zip函数
  3. [PHP] 网络与协议
  4. this 自引用指针
  5. carry函数在C语言中用法,CArry的使用完整版.doc
  6. 学习了pr后的收获_零基础如何学习PR影视剪辑以及调色?
  7. 网页木马是什么原理?
  8. 云erp系统、进销存软件、仓储管理系统之间有哪些区别
  9. 【学习中】王者荣耀游戏拆解分析(1)
  10. (己解决)黑苹果驱动英特尔核显疑问记录
  11. 图片在线编辑器怎么使用教程
  12. HUAWEI Sound Joy首发体验,独具一格的华为音质究竟如何呢?
  13. Service Mesh介绍
  14. windows 远程 登录无操作30分钟后自动退出登录_【计时优易学车远程教育学习流程】...
  15. Java笔记14-Java高级编程部分-第八章-多线程
  16. JavaScript数据数据类型判断
  17. 解密体育背后AI黑科技:花样滑冰动作识别、多模视频分类和精彩片段剪辑
  18. 很遗憾,你们的问题我无法回答--Leo谈应届生求职 10
  19. 用户需求说明书和产品规格需求说明书的区别
  20. 滴滴技术牛逼吗?看它开源了哪些有意思的项目

热门文章

  1. luogu1984 烧水问题 (找规律)
  2. vue.js 源代码学习笔记 ----- instance inject
  3. Think in Java ---Chapter 8 多态 [基础的混凝土大厦]
  4. Sqoop导入到hdfs
  5. HTML 5 新标签
  6. 快速得到容器ID和veth bridge interface的关系
  7. HCIE Security 流量型攻击防范 备考笔记(幕布)
  8. CICD详解(五)——SVN安装与配置
  9. 自建CA生成证书详解
  10. L2TP详解(五)——Client Initiated隧道和会话建立过程