热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

nginx源码分析——模块、初始化

1.nginx有哪些模块?要知道nginx有哪些模块,一个快速的方法就是编译nginx。编译之后,会在源代码根目录下生成objs目录,该目录中包含有ngx_auto_config.h和ngx_au

1. nginx有哪些模块?

 

要知道nginx有哪些模块,一个快速的方法就是编译nginx。编译之后,会在源代码根目录下生成objs目录,该目录中包含有ngx_auto_config.hngx_auto_headers.h,以及ngx_modules.c文件,当然,还有Makefile文件等。

 

其中,生成的ngx_modules.c文件中,重新集中申明(使用extern关键字)nginx配置的所有模块,这些模块可通过编译前的configure命令进行配置,即设置哪些模块需要编译,哪些不被编译。如下。

00001:
00002: #include
00003: #include
00004:
00005:
00006:
00007: extern ngx_module_t ngx_core_module;
00008: extern ngx_module_t ngx_errlog_module;
00009: extern ngx_module_t ngx_conf_module;
00010: extern ngx_module_t ngx_events_module;
00011: extern ngx_module_t ngx_event_core_module;
00012: extern ngx_module_t ngx_epoll_module;
00013: extern ngx_module_t ngx_http_module;
00014: extern ngx_module_t ngx_http_core_module;
00015: extern ngx_module_t ngx_http_log_module;
00016: extern ngx_module_t ngx_http_upstream_module;
00017: extern ngx_module_t ngx_http_static_module;
00018: extern ngx_module_t ngx_http_autoindex_module;
00019: extern ngx_module_t ngx_http_index_module;
00020: extern ngx_module_t ngx_http_auth_basic_module;
00021: extern ngx_module_t ngx_http_access_module;
00022: extern ngx_module_t ngx_http_limit_zone_module;
00023: extern ngx_module_t ngx_http_limit_req_module;
00024: extern ngx_module_t ngx_http_geo_module;
00025: extern ngx_module_t ngx_http_map_module;
00026: extern ngx_module_t ngx_http_split_clients_module;
00027: extern ngx_module_t ngx_http_referer_module;
00028: extern ngx_module_t ngx_http_rewrite_module;
00029: extern ngx_module_t ngx_http_proxy_module;
00030: extern ngx_module_t ngx_http_fastcgi_module;
00031: extern ngx_module_t ngx_http_uwsgi_module;
00032: extern ngx_module_t ngx_http_scgi_module;
00033: extern ngx_module_t ngx_http_memcached_module;
00034: extern ngx_module_t ngx_http_empty_gif_module;
00035: extern ngx_module_t ngx_http_browser_module;
00036: extern ngx_module_t ngx_http_upstream_ip_hash_module;
00037: extern ngx_module_t ngx_http_stub_status_module;
00038: extern ngx_module_t ngx_http_write_filter_module;
00039: extern ngx_module_t ngx_http_header_filter_module;
00040: extern ngx_module_t ngx_http_chunked_filter_module;
00041: extern ngx_module_t ngx_http_range_header_filter_module;
00042: extern ngx_module_t ngx_http_gzip_filter_module;
00043: extern ngx_module_t ngx_http_postpone_filter_module;
00044: extern ngx_module_t ngx_http_ssi_filter_module;
00045: extern ngx_module_t ngx_http_charset_filter_module;
00046: extern ngx_module_t ngx_http_userid_filter_module;
00047: extern ngx_module_t ngx_http_headers_filter_module;
00048: extern ngx_module_t ngx_http_copy_filter_module;
00049: extern ngx_module_t ngx_http_range_body_filter_module;
00050: extern ngx_module_t ngx_http_not_modified_filter_module;
00051:

很显然,这些模块均是在此处用extern进行申明,以表明其他模块可以访问,而对其本身的定义和初始化ngx_module_t结构在其对应的.c文件中进行。例如,ngx_core_module模块便是在./src/core/nginx.c文件中定义并进行静态初始化。实际上,ngx_core_module是一个全局的结构体对象,其他模块类同。如下。

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
};

2. nginx如何描述这些模块?

 

2.1模块数据结构

 

2.1.1 ngx_module_t结构

 

nginx的模块化架构最基本的数据结构为ngx_module_t,因此,此处,我们先分析这个结构,在./src/core/ngx_conf_file.h文件中定义。如下,//后的内容为笔者加入的注释。

#define NGX_MODULE_V1          0, 0, 0, 0, 0, 0, 1
#define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0

//模块的数据结构定义
struct ngx_module_s {
ngx_uint_t ctx_index; //分类模计数器
ngx_uint_t index; //模块计数器

ngx_uint_t spare0;
ngx_uint_t spare1;
ngx_uint_t spare2;
ngx_uint_t spare3;

ngx_uint_t version; //版本

void *ctx; //该模块的上下文,也就是说指向的是哪一个模块,core或者event或者http或者mail,conf
ngx_command_t *commands; //该模块的命令集,指向一个ngx_command_t结构数组
ngx_uint_t type; //该模块的种类,为core/event/http/mail中的一种

ngx_int_t (*init_master)(ngx_log_t *log); //初始化master

ngx_int_t (*init_module)(ngx_cycle_t *cycle); //初始化模块

ngx_int_t (*init_process)(ngx_cycle_t *cycle); //初始化工作进程的时候调用
ngx_int_t (*init_thread)(ngx_cycle_t *cycle); //初始化线程的时候调用
void (*exit_thread)(ngx_cycle_t *cycle); //退出线程
void (*exit_process)(ngx_cycle_t *cycle); //退出进程

void (*exit_master)(ngx_cycle_t *cycle); //退出master

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;
};

其中,init_master, init_module, init_process, init_thread, exit_thread, exit_process, exit_master分别在初始化master、初始化模块、初始化工作进程、初始化线程、退出线程、退出工作进程、退出master时被调用。

 

2.1.2 ngx_command_t结构

 

模块的命令集commands指向一个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;
};

2.2模块类图

 

nginxC语言开发的开源高性能web server,其代码中大量使用了callback方式,例如模块结构ngx_module_t中的init_master等。实际上,我们可以将ngx_module_t看作C++的一个类,其中的数据字段便是其属性,而那些callback便是该类的操作。

 

——这应该就是nginx的模块化思想。画出的ngx_module_t的类图如下。

3.nginx如何组织这些模块?

 

3.1全局数组ngx_modules

 

由第1节,我们知道,nginx拥有几十个模块,那么,这些模块是如何组织的呢?

 

——保存在一个全局指针数组ngx_modules[]中,数组的每一个元素均为一个全局ngx_module_t对象的指针。如下。请参考./objs/ngx_modules.c文件中的定义。

00052: ngx_module_t *ngx_modules[] = {
00053: &ngx_core_module,
00054: &ngx_errlog_module,
00055: &ngx_conf_module,
00056: &ngx_events_module,
00057: &ngx_event_core_module,
00058: &ngx_epoll_module,
00059: &ngx_http_module,
00060: &ngx_http_core_module,
00061: &ngx_http_log_module,
00062: &ngx_http_upstream_module,
00063: &ngx_http_static_module,
00064: &ngx_http_autoindex_module,
00065: &ngx_http_index_module,
00066: &ngx_http_auth_basic_module,
00067: &ngx_http_access_module,
00068: &ngx_http_limit_zone_module,
00069: &ngx_http_limit_req_module,
00070: &ngx_http_geo_module,
00071: &ngx_http_map_module,
00072: &ngx_http_split_clients_module,
00073: &ngx_http_referer_module,
00074: &ngx_http_rewrite_module,
00075: &ngx_http_proxy_module,
00076: &ngx_http_fastcgi_module,
00077: &ngx_http_uwsgi_module,
00078: &ngx_http_scgi_module,
00079: &ngx_http_memcached_module,
00080: &ngx_http_empty_gif_module,
00081: &ngx_http_browser_module,
00082: &ngx_http_upstream_ip_hash_module,
00083: &ngx_http_stub_status_module,
00084: &ngx_http_write_filter_module,
00085: &ngx_http_header_filter_module,
00086: &ngx_http_chunked_filter_module,
00087: &ngx_http_range_header_filter_module,
00088: &ngx_http_gzip_filter_module,
00089: &ngx_http_postpone_filter_module,
00090: &ngx_http_ssi_filter_module,
00091: &ngx_http_charset_filter_module,
00092: &ngx_http_userid_filter_module,
00093: &ngx_http_headers_filter_module,
00094: &ngx_http_copy_filter_module,
00095: &ngx_http_range_body_filter_module,
00096: &ngx_http_not_modified_filter_module,
00097: NULL
00098: };
00099:

3.2模块组织结构图

 

44个模块,这些模块的组织结构图如下所示,因模块较多,图中只画出一部分有代表性的重要模块。 

4. nginx的模块种类

 

在对全局数组ngx_modules进行初始化时,即对每一个模块进行了静态初始化。其中对模块的type字段的初始化是通过以下4个宏进行的。

 

(1)文件./src/core/ngx_conf_file.h

#define NGX_CORE_MODULE      0x45524F43   /* "CORE" */
#define NGX_CONF_MODULE 0x464E4F43 /* "CONF" */

(2) 文件 ./src/event/ngx_event.h

#define NGX_EVENT_MODULE      0x544E5645  /* "EVNT" */
#define NGX_EVENT_MODULE 0x544E5645 /* "EVNT" */


(3)文件./src/http/ngx_http_config.h

#define NGX_HTTP_MODULE       0x50545448  /* "HTTP" */

即模块种类宏,定义为一个十六进制的数,这个十六进制的数就是其类型对应的ASCII码。因此,nginx共有4种类型的模块,分别为"CORE","CONF","EVNT","HTTP"

 

实际上,如果在configure阶段,使用了"--with-mail"参数,mail模块将被编译进来,其对应的宏如下。

#define NGX_MAIL_MODULE       0x4C49414D  /* "MAIL" */

因此,严格来讲,nginx5中类型的模块,"CORE","CONF","EVNT","HTTP","MAIL"

5. nginx如何初始化这些模块?

 

5.1静态初始化

 

即编译期间完成的数据成员初始化。记mname为某个模块的名字,其静态初始化过程如下。

(1)用宏NGX_MODULE_V1初始化前7个字段

(2)用全局对象ngx_mname_module_ctx的地址初始化ctx指针

(3)用全局数组ngx_mname_commands[]初始化commands指针

(4)用宏NGX_CORE_MODULE等初始化type字段

(5)初始化init_mastercallback

(6)用宏NGX_MODULE_V1_PADDING初始化最后8个字段

 

由此可见,在定义该模块(全局结构对象)时,将其ctx_indexindex均初始化为0。因此,模块的静态初始化(数据成员初始化)实际上只是对模块上下文、模块命令集和模块类型进行初始化。

 

5.2动态初始化

 

nginx运行(启动)初期,对模块本身的初始化。

 

5.2.1 index字段的初始化

 

对各个模块的index字段的初始化是在main函数中进行的,如下。

00325:    ngx_max_module = 0;
00326: for (i = 0; ngx_modules[i]; i++) {
00327: ngx_modules[i]->index = ngx_max_module++;
00328: }

可见,该for-loop执行后,每个模块的index值便是其在ngx_modules[]数组中的下标值,且全局变量ngx_max_module为模块个数,对于本例来讲,ngx_max_module=44

 

5.2.2 ctx_index字段的初始化

 

(1) "EVNT"类型的模块

00877: static char *
00878: ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
00879: {
00880: char *rv;
00881: void ***ctx;
00882: ngx_uint_t i;
00883: ngx_conf_t pcf;
00884: ngx_event_module_t *m;
00885:
00886: /* count the number of the event modules and set up their indices */
00887:
00888: ngx_event_max_module = 0;
00889: for (i = 0; ngx_modules[i]; i++) {
00890: if (ngx_modules[i]->type ! = NGX_EVENT_MODULE) {
00891: continue;
00892: }
00893:
00894: ngx_modules[i]->ctx_index = ngx_event_max_module++;
00895: }
00896:
...

(2) "HTTP"类型的模块

00117: static char *
00118: ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
00119: {
00120: char *rv;
00121: ngx_uint_t mi, m, s;
00122: ngx_conf_t pcf;
00123: ngx_http_module_t *module;
00124: ngx_http_conf_ctx_t *ctx;
00125: ngx_http_core_loc_conf_t *clcf;
00126: ngx_http_core_srv_conf_t **cscfp;
00127: ngx_http_core_main_conf_t *cmcf;
00128:
00129: /* the main http context */
00130:
00131: ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
00132: if (ctx == NULL) {
00133: return NGX_CONF_ERROR;
00134: }
00135:
00136: *(ngx_http_conf_ctx_t **) cOnf= ctx;
00137:
00138:
00139: /* count the number of the http modules and set up their indices */
00140:
00141: ngx_http_max_module = 0;
00142: for (m = 0; ngx_modules[m]; m++) {
00143: if (ngx_modules[m]->type ! = NGX_HTTP_MODULE) {
00144: continue;
00145: }
00146:
00147: ngx_modules[m]->ctx_index = ngx_http_max_module++;
00148: }
00149:
...

(3) "MAIL" 类型的模块

00072: static char *
00073: ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
00074: {
00075: char *rv;
00076: ngx_uint_t i, m, mi, s;
00077: ngx_conf_t pcf;
00078: ngx_array_t ports;
00079: ngx_mail_listen_t *listen;
00080: ngx_mail_module_t *module;
00081: ngx_mail_conf_ctx_t *ctx;
00082: ngx_mail_core_srv_conf_t **cscfp;
00083: ngx_mail_core_main_conf_t *cmcf;
00084:
00085: if (cmd->name.data[0] == 'i') {
00086: ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
00087: "the \"imap\" directive is deprecated, "
00088: "use the \"mail\" directive instead");
00089: }
00090:
00091: /* the main mail context */
00092:
00093: ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t));
00094: if (ctx == NULL) {
00095: return NGX_CONF_ERROR;
00096: }
00097:
00098: *(ngx_mail_conf_ctx_t **) cOnf= ctx;
00099:
00100: /* count the number of the http modules and set up their indices */
00101:
00102: ngx_mail_max_module = 0;
00103: for (m = 0; ngx_modules[m]; m++) {
00104: if (ngx_modules[m]->type ! = NGX_MAIL_MODULE) {
00105: continue;
00106: }
00107:
00108: ngx_modules[m]->ctx_index = ngx_mail_max_module++;
00109: }
00110:
...

5.2.3其他初始化

其他的初始化工作,将在nginx启动及其进程启动分析中介绍。

 

6.小结

本文主要讲述了nginx的模块及其初始化,包括所有模块的组织,及模块的静态初始化和部分动态初始化。

 

 

Reference

nginx-1.0.4源码

http://nginx.org/en


转自:

http://blog.csdn.net/livelylittlefish/article/details/6571497


推荐阅读
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • 本文介绍了在实现了System.Collections.Generic.IDictionary接口的泛型字典类中如何使用foreach循环来枚举字典中的键值对。同时还讨论了非泛型字典类和泛型字典类在foreach循环中使用的不同类型,以及使用KeyValuePair类型在foreach循环中枚举泛型字典类的优势。阅读本文可以帮助您更好地理解泛型字典类的使用和性能优化。 ... [详细]
  • 1、etcnginxconf.ddefault.conf,添加如下信息:location{try_files$uri$urirouter;rootho ... [详细]
  • 源码安装Nginx 解决报错
    CentOS8源码安装Nginx编译安装注意事项如果安装时不是使用的默认路径,则必须要修改PATH环境变量,以能够识别此程序的二进制文件路径 ... [详细]
  • Word2vec,Fasttext,Glove,Elmo,Bert,Flairpre-trainWordEmbedding源码数据Github网址:词向量预训练实现Githubf ... [详细]
  • 直接从网上下载redis当然你也可以直接从别的地方拿过来直接放在redis中[root@iZ2zedckzf8nczp6xshv4mZ]#wgethttp:download ... [详细]
  • 对于WEB应用集群的技术实现而言,最大的难点就是如何能在集群中的多个节点之间保持数据的一致性,会话(Session)信息是这 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 本文介绍了Android中的assets目录和raw目录的共同点和区别,包括获取资源的方法、目录结构的限制以及列出资源的能力。同时,还解释了raw目录中资源文件生成的ID,并说明了这些目录的使用方法。 ... [详细]
  • 本文概述了JNI的原理以及常用方法。JNI提供了一种Java字节码调用C/C++的解决方案,但引用类型不能直接在Native层使用,需要进行类型转化。多维数组(包括二维数组)都是引用类型,需要使用jobjectArray类型来存取其值。此外,由于Java支持函数重载,根据函数名无法找到对应的JNI函数,因此介绍了JNI函数签名信息的解决方案。 ... [详细]
  • Makefile基本用法
    来源https:www.gnu.orgsoftwaremakemanualmake.pdf简单的例子其中的cc通过链接,间接指向usrbingcc。Makefile文件中列出了依赖 ... [详细]
  • nagios插件内存监控
    为什么80%的码农都做不了架构师?#!usrbinenvpython#-*-coding:utf-8-*-NagiosplugintoreportMe ... [详细]
author-avatar
手机用户2602920905
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有