ImageVerifierCode 换一换
格式:DOCX , 页数:24 ,大小:114.08KB ,
资源ID:6507547      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6507547.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Nginx源代码分析.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Nginx源代码分析.docx

1、Nginx源代码分析Nginx源代码分析1. Nginx代码的目录和结构nginx的源码目录结构层次明确,从自动编译脚本到各级的源码,层次都很清晰,是一个大型服务端软件构建的一个范例。以下是源码目录结构说明:auto 自动编译安装相关目录 cc 针对各种编译器进行相应的编译配置目录,包括Gcc、Ccc等 lib 程序依赖的各种库,包括md5,openssl,pcre等 os 针对不同操作系统所做的编译配置目录 typesconf 相关配置文件等目录,包括nginx的配置文件、fcgi相关的配置等contribhtml index.htmlsrc 源码目录core 核心源码目录,包括定义常用数据

2、结构、体系结构实现等event 封装的事件系统源码目录http http服务器实现目录mail 邮件代码服务器实现目录misc 该目录当前版本只包含google perftools包os nginx对各操作系统下的函数进行封装以及实现核心调用的目录。2. 基本数据结构2.1. 简单的数据类型在 core/ngx_config.h 目录里面定义了基本的数据类型的映射,大部分都映射到c语言自身的数据类型。typedef intptr_t ngx_int_t;typedef uintptr_t ngx_uint_t;typedef intptr_t ngx_flag_t;其中ngx_int_t,ng

3、inx_flag_t,都映射为intptr_t; ngx_uint_t映射为uintptr_t。这两个类型在/usr/include/stdint.h的定义为:/* Types for void * pointers. */#if _WORDSIZE = 64# ifndef _intptr_t_definedtypedef long int intptr_t;# define _intptr_t_defined# endiftypedef unsigned long int uintptr_t;#else# ifndef _intptr_t_definedtypedef int intptr

4、_t;# define _intptr_t_defined# endiftypedef unsigned int uintptr_t;#endif所以基本的操作和整形/指针类型的操作类似。2.2. 字符串的数据类型nginx对c语言的字符串类型进行了简单的封装,core/ngx_string.h/c里面包含这些封装的内容。其中定义了ngx_str_t,ngx_keyval_t, ngx_variable_value_t这几个基础类型的定义如下:typedef struct size_t len; u_char *data; ngx_str_t;typedef struct ngx_str_t

5、key; ngx_str_t value; ngx_keyval_t;typedef struct unsigned len:28; unsigned valid:1; unsigned no_cacheable:1; unsigned not_found:1; unsigned escape:1; u_char *data; ngx_variable_value_t;可以看出 ngx_str_t 在原有的uchar*的基础上加入的字符串长度的附加信息, 初始化使用ngx_string宏进行,他的定义为:#define ngx_string(str) sizeof(str) - 1, (u_c

6、har *) str 2.3. 内存分配相关(1) 系统功能封装内存相关的操作主要在 os/unix/ngx_alloc.h,c 和 core/ngx_palloc.h,c 下。其中 os/unix/ngx_alloc.h,c 封装了最基本的内存分配函数,是对c原有的malloc/free/memalign 等原有的函数的封装,对应的函数为: ngx_alloc 使用malloc分配内存空间 ngx_calloc 使用malloc分配内存空间,并且将空间内容初始化为0 ngx_memalign 返回基于一个指定的alignment大小的数值为对齐基数的空间 ngx_free 对内存的释放操作(

7、2) Nginx的内存池为了方便系统模块对内存的使用,方便内存的管理,nginx自己实现了进程池的机制来进行内存的分配和释放, 首先nginx会在特定的生命周期帮你统一建立内存池,当需要进行内存分配的时候统一通过内存池中的内存进行分配,最后nginx会在适当的时候释放内存池的资源,开发者只要在需要的时候对内存进行申请即可,不用过多考虑内存的释放等问题,大大提高了开发的效率。内存池的主要结构为:/ngx_palloc.hstruct ngx_pool_s ngx_pool_data_t d; size_t max; ngx_pool_t *current; ngx_chain_t *chain;

8、 ngx_pool_large_t *large; ngx_pool_cleanup_t *cleanup; ngx_log_t *log;/ngx_core.htypedef struct ngx_pool_s ngx_pool_t;typedef struct ngx_chain_s ngx_chain_t;下面解释一下主要的几个操作:/ 创建内存池ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);大致的过程是创建使用 ngx_alloc 分配一个size大小的空间, 然后将ngx_pool_t*指向这个空间, 并且初始化里面

9、的成员, 其中p-d.last = (u_char *) p + sizeof(ngx_pool_t); / 初始指向 ngx_pool_t 结构体后面p-d.end = (u_char *) p + size; / 整个结构的结尾后面p-max = (size last指针重新指向 ngx_pool_t 结构之后(和创建时一样)/ 从内存池里分配内存void *ngx_palloc(ngx_pool_t *pool, size_t size);void *ngx_pnalloc(ngx_pool_t *pool, size_t size);void *ngx_pcalloc(ngx_pool

10、_t *pool, size_t size);void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);ngx_palloc的过程一般为,首先判断待分配的内存是否大于 pool-max的大小,如果大于则使用 ngx_palloc_large 在 large 链表里分配一段内存并返回, 如果小于测尝试从链表的 pool-current 开始遍历链表,尝试找出一个可以分配的内存,当链表里的任何一个节点都无法分配内存的时候,就调用 ngx_palloc_block 生成链表里一个新的节点, 并在新的节点里分配内存并返回,

11、 同时, 还会将pool-current 指针指向新的位置(从链表里面pool-d.failed小于等于4的节点里找出) ,其他几个函数也基本上为 ngx_palloc 的变种,实现方式大同小异/ 释放指定的内存ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);这个操作只有在内存在large链表里注册的内存在会被真正释放,如果分配的是普通的内存,则会在destory_pool的时候统一释放./ 注册cleanup回叫函数(结构体)ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_

12、t size);这个过程和我们之前经常使用的有些区别, 他首先在传入的内存池中分配这个结构的空间(包括data段), 然后将为结构体分配的空间返回, 通过操作返回的ngx_pool_cleanup_t结构来添加回叫的实现。 (这个过程在nginx里面出现的比较多,也就是 xxxx_add 操作通常不是实际的添加操作,而是分配空间并返回一个指针,后续我们还要通过操作指针指向的空间来实现所谓的add)2.4. Nginx的基本容器(1) ngx_array对应的文件为 core/ngx_array.c|hngx_array是nginx内部封装的使用 ngx_pool_t对内存池进行分配的数组容器,

13、其中的数据是在一整片内存区中连续存放的。更新数组时只能在尾部压入1个或多个元素。数组的实现结构为:struct ngx_array_s void *elts; ngx_uint_t nelts; size_t size; ngx_uint_t nalloc; ngx_pool_t *pool;其中 elts 为具体的数据区域的指针, nelts 为数组实际包含的元素数量, size为数组单个元素的大小, nalloc为数组容器预先(或者重新)分配的内存大小, pool 为分配基于的内存池常用的操作有:/ 创建一个新的数组容器ngx_array_t *ngx_array_create(ngx_p

14、ool_t *p, ngx_uint_t n, size_t size);/ 销毁数组容器void ngx_array_destroy(ngx_array_t *a);/ 将新的元素加入数组容器void *ngx_array_push(ngx_array_t *a);void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);/返回个元素的指针这里需要注意的是,和之前的ngx_pool_cleanup_add一样, ngx_array_push只是进行内存分配的操作,我们需要对返回的指针指向的地址进行赋值等操作来实现实际数组值的添加。具体一点的pu

15、sh操作的实现为:1. 首先判断nalloc是否和nelts相等,即数组预先分配的空间已经满了,如果没满则计算地址直接返回指针2. 如果已经满了则先判断是否我们的pool中的当前链表节点还有剩余的空间,如果有则直接在当前的pool链表节点中分配内存,并返回3. 如果当前链表节点没有足够的空间则使用ngx_palloc重新分配一个2倍于之前数组空间大小的数组,然后将数据转移过来,并返回新地址的指针(2) ngx_queuengx_queue.c,h 实现了一个队列的操作逻辑,队列的基本结构为一个双向队列基础的数据结构为:typedef struct ngx_queue_s ngx_queue_t

16、;struct ngx_queue_s ngx_queue_t *prev; ngx_queue_t *next;注意nginx的队列操作和结构只进行指针的操作,不负责节点内容空间的分配和保存,所以在定义自己的队列节点的时候,需要自己定义数据结构以及分配空间, 并包含一个ngx_queue_t类型的成员, 需要获得原始的数据节点的时候需要使用ngx_queue_data宏:#define ngx_queue_data(q, type, link) (type *) (u_char *) q - offsetof(type, link)另外,整个queue结构中包含一个 sentinel(哨兵)

17、 节点, 他指向队列的头和尾。(3) ngx_hashngx_hash.c|h 实现了nginx里面比较重要的一个hash结构, 这个在模块配置解析里经常被用到。该 hash 结构是只读的,即仅在初始创建时可以给出保存在其中的 key-val 对,其后就只能查询而不能进行增删改操作了。下面是简单 hash 结构的内存布局:虽然代码理解起来比较混乱,但是使用还是比较简单的,常用的有创建 hash 和在 hash 中进行查找两个操作,对于创建hash的操作,过程一般为:1. 构造一个 ngx_hash_key_t 为成员的数组, 包含 key, value 和 使用key计算出的一个hash值2.

18、 构建一个 ngx_hash_init_t结构体的变量, 其中包含了ngx_hash_t 的成员, 为hash的结构体, 还包括一些其他初始设置,如bucket的大小,内存池等3. 调用 ngx_hash_init 传入 ngx_hash_init_t 结构, ngx_hash_key_t 的数组,和数组的长度, 进行初始化,这样 ngx_hash_init_t的hash成员就是我们要的hash结构查找的过程很简单1. 计算 key 的hash值2. 使用 ngx_hash_find 进行查找,需要同时传入 hash值和key ,返回的就是value的指针需要注意的是,nginx 的 hash

19、 在查找时使用的是分桶后线性查找法,因此当分桶数确定时查找效率同其中的总 key-val 对数量成反比。(4) ngx_listngx_list 的结构并不复杂,ngx为我们封装了ngx_list_create, ngx_list_init, 和 ngx_list_push等(建立,初始化,添加)操作, 但是对于我们来说最常用的是遍历操作, 下面是nginx的注释里面提到的遍历的例子 part = &list.part; data = part-elts; for (i = 0 ; i+) if (i = part-nelts) if (part-next = NULL) break; par

20、t = part-next; data = part-elts; i = 0; . datai . (5) ngx_buf对应的文件为 core/ngx_buf.c|hbuf分为两种类型,一种是file,一种是memory.因此这里会有文件的一些操作域。 可以看到buf相对于pool多了一个pos域(file_pos).这里我们要知道我们发送往套接字异或者其他的设备,我们这里会现将数据放到buf中,然后当设备或者套接字准备好了,我们就会从buf中读取,因此这里pos指针就是放到buf中的已经被执行的数据(也就是已经送往套接字)的位置。struct ngx_buf_s /pos表示已经执行的数据

21、的位置。 u_char *pos;/last和上面内存池中last一样,也就是使用的内存的最后一个字节的指针 u_char *last;/文件指针 off_t file_pos; off_t file_last;/buf的开始指针 u_char *start; /* start of buffer */ u_char *end; /* end of buffer */这里表示这个buf从属于那个模块。 ngx_buf_tag_t tag; ngx_file_t *file; ngx_buf_t *shadow;/一些标记 /* the bufs content could be changed

22、 */ unsigned temporary:1;/在内存中是不能改变的。 unsigned memory:1;/是否是mmap的内存 unsigned mmap:1; unsigned recycled:1;/是否文件。 unsigned in_file:1; unsigned flush:1; unsigned sync:1; unsigned last_buf:1; unsigned last_in_chain:1; unsigned last_shadow:1; unsigned temp_file:1; /* STUB */ int num;3. nginx的core module

23、的结构和运行机制3.1. ngx_init_cycle其中一个比较重要的函数调用是, ngx_init_cycle, 这个是使用kscope输出的他的调用关系,他被main, ngx_master_process_cycle,ngx_single_process_cycle 调用, 其中后两者是在reconfigure的时候被调用的他主要做了如下几件事情:初始化cycle是基于旧有的cycle进行的,比如这里的 init_cycle,会继承old cycle的很多属性, 比如log等, 但是同时会对很多资源重新分配,比如pool, shared mem, file handler, liste

24、ning socket 等,同时清除旧有的cycle的资源 另外,ngx_master/single_process_cycle 里面会对init_process进行调用, 并且循环调用 ngx_process_events_and_timers , 其中里面会调用ngx_process_events(cycle, timer, flags); 对事件循环进行polliing 时间一般默认为 500 ms。Nginx的OS module的结构和运行机制4. nginx的http module 的结构和运行机制HTTP相关的Module都在 src/http 目录和其子目录下, 其中 src/h

25、ttp 下的文件为http模块的核心文件, src/http/modules 下的文件为http模块的扩展模块。4.1. ngx_http.c|hngx_http.c 中,注册了 http 这个指令的处理模块,对应ngx_http_block函数static ngx_command_t ngx_http_commands = ngx_string(http), NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, ngx_http_block, 0, 0, NULL , ngx_null_command;这个函数里面会进行一些conf资源分配/Merge,

26、配置文件解析等工作。 这里面有个一比较重要的工作是注册了nginx http 的 phase handler if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) return NGX_CONF_ERROR; phase handler的类型在 ngx_http_core_module 这里定义:typedef enum NGX_HTTP_POST_READ_PHASE = 0, NGX_HTTP_SERVER_REWRITE_PHASE, NGX_HTTP_FIND_CONFIG_PHASE, NGX_HTTP_REWRITE_PHASE

27、, NGX_HTTP_POST_REWRITE_PHASE, NGX_HTTP_PREACCESS_PHASE, NGX_HTTP_ACCESS_PHASE, NGX_HTTP_POST_ACCESS_PHASE, NGX_HTTP_TRY_FILES_PHASE, NGX_HTTP_CONTENT_PHASE, NGX_HTTP_LOG_PHASE ngx_http_phases;每一个phase的handlers 都是一个数组,里面可以包含多个元素,通过 ngx_array_push 添加新的handler。其中每个phase的处理大都包含了对ngx_request_t 的 write 或

28、者 read event的改写,其中在 ngx_http_core_content_phase 里面, 有对location handler的调用, 其中的 r-content_handler 就是运行时刻从location handler中注册的, if (r-content_handler) r-write_event_handler = ngx_http_request_empty_handler; ngx_http_finalize_request(r, r-content_handler(r); /*实际的请求发送处理*/ return NGX_OK; 其中, 在各个phase的结束阶段,一般都是调用 r-phase_handler+; r

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1