Update chapter_02.rst

some typos
This commit is contained in:
RocFang 2014-01-28 16:09:02 +08:00
parent faf58914a5
commit 48d3b8fd67
1 changed files with 15 additions and 15 deletions

View File

@ -179,7 +179,7 @@ ngx_str_t(100%)
u_char *data;
} ngx_str_t;
结构体当中data指向字符串数据的第一个字符字符串的结束用长度来表示而不是由'\\0'来表示结束。所以在写nginx代码时处理字符串的方法跟我们平时使用有很大的不一样但要时刻记住字符串不以'\\0'结束尽量使用nginx提供的字符串操作的api来操作字符串。
结构体当中data指向字符串数据的第一个字符字符串的结束用长度来表示而不是由'\\0'来表示结束。所以在写nginx代码时处理字符串的方法跟我们平时使用有很大的不一样但要时刻记住字符串不以'\\0'结束尽量使用nginx提供的字符串操作的api来操作字符串。
那么nginx这样做有什么好处呢首先通过长度来表示字符串长度减少计算字符串长度的次数。其次nginx可以重复引用一段字符串内存data可以指向任意内存长度表示结束而不用去copy一份自己的字符串(因为如果要以'\\0'结束而不能更改原字符串所以势必要copy一段字符串)。我们在ngx_http_request_t结构体的成员中可以找到很多字符串引用一段内存的例子比如request_line、uri、args等等这些字符串的data部分都是指向在接收数据时创建buffer所指向的内存中uriargs就没有必要copy一份出来。这样的话减少了很多不必要的内存分配与拷贝。
正是基于此特性在nginx中必须谨慎的去修改一个字符串。在修改字符串时需要认真的去考虑是否可以修改该字符串字符串修改后是否会对其它的引用造成影响。在后面介绍ngx_unescape_uri函数的时候就会看到这一点。但是使用nginx的字符串会产生一些问题glibc提供的很多系统api函数大多是通过'\\0'来表示字符串的结束所以我们在调用系统api时就不能直接传入str->data了。此时通常的做法是创建一段str->len + 1大小的内存然后copy字符串最后一个字节置为'\\0'。比较hack的做法是将字符串最后一个字符的后一个字符backup一个然后设置为'\\0'在做完调用后再由backup改回来但前提条件是你得确定这个字符是可以修改的而且是有内存分配不会越界但一般不建议这么做。
接下来看看nginx提供的操作字符串相关的api。
@ -389,9 +389,9 @@ ngx_pool_t是一个非常重要的数据结构在很多重要的场合都有
例如对于内存的管理如果我们需要使用内存那么总是从一个ngx_pool_t的对象中获取内存在最终的某个时刻我们销毁这个ngx_pool_t对象所有这些内存都被释放了。这样我们就不必要对对这些内存进行malloc和free的操作不用担心是否某块被malloc出来的内存没有被释放。因为当ngx_pool_t对象被销毁的时候所有从这个对象中分配出来的内存都会被统一释放掉。
比如我们要使用一系列的文件但是我们打开以后最终需要都关闭那么我们就把这些文件统一登记到一个ngx_pool_t对象中当这个ngx_pool_t对象被销毁的时候所有这些文件都将会被关闭。
比如我们要使用一系列的文件但是我们打开以后最终需要都关闭那么我们就把这些文件统一登记到一个ngx_pool_t对象中当这个ngx_pool_t对象被销毁的时候所有这些文件都将会被关闭。
从上面举的两个例子中我们可以看出使用ngx_pool_t这个数据结构的时候所有的资源的释放都在这个对象被销毁的时刻统一进行了释放那么就会带来一个问题就是这些资源的生存周期或者说被占用的时间是跟ngx_pool_t的生存周期基本一致ngx_pool_t也提供了少量操作可以提前释放资源。从最高效的角度来说这并不是最好的。比如我们需要依次使用ABC三个资源且使用完B的时候A就不会再被使用了使用C的时候A和B都不会被使用到。如果不使用ngx_pool_t来管理这三个资源那我们可能从系统里面申请A使用A然后在释放A。接着申请B使用B再释放B。最后申请C使用C然后释放C。但是当我们使用一个ngx_pool_t对象来管理这三个资源的时候AB和C的释放是在最后一起发生的也就是在使用完C以后。诚然这在客观上增加了程序在一段时间的资源使用量。但是这也减轻了程序员分别管理三个资源的生命周期的工作。这也就是有所得必有所失的道理。实际上是一个取舍的问题在具体的情况下你更在乎的是哪个。
从上面举的两个例子中我们可以看出使用ngx_pool_t这个数据结构的时候所有的资源的释放都在这个对象被销毁的时刻统一进行了释放那么就会带来一个问题就是这些资源的生存周期或者说被占用的时间是跟ngx_pool_t的生存周期基本一致ngx_pool_t也提供了少量操作可以提前释放资源。从最高效的角度来说这并不是最好的。比如我们需要依次使用ABC三个资源且使用完B的时候A就不会再被使用了使用C的时候A和B都不会被使用到。如果不使用ngx_pool_t来管理这三个资源那我们可能从系统里面申请A使用A然后在释放A。接着申请B使用B再释放B。最后申请C使用C然后释放C。但是当我们使用一个ngx_pool_t对象来管理这三个资源的时候AB和C的释放是在最后一起发生的也就是在使用完C以后。诚然这在客观上增加了程序在一段时间的资源使用量。但是这也减轻了程序员分别管理三个资源的生命周期的工作。这也就是有所得必有所失的道理。实际上是一个取舍的问题要看在具体的情况下,你更在乎的是哪个。
可以看一下在nginx里面一个典型的使用ngx_pool_t的场景对于nginx处理的每个http request, nginx会生成一个ngx_pool_t对象与这个http request关联所有处理过程中需要申请的资源都从这个ngx_pool_t对象中获取当这个http request处理完成以后所有在处理过程中申请的资源都将随着这个关联的ngx_pool_t对象的销毁而释放。
@ -471,7 +471,7 @@ ngx_pool_t相关结构及操作被定义在文件src/core/ngx_palloc.h|c中。
ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
ngx_pool_t中的cleanup字段管理着一个特殊的链表该链表的每一项都记录着一个特殊的需要释放的资源。对于这个链表中每个节点所包含的资源如何去释放是自说明的。这也就提供了非常大的灵活性。意味着ngx_pool_t不仅仅可以管理内存通过这个机制也可以管理任何需要释放的资源例如关闭文件或者删除文件等等。下面我们看一下这个链表每个节点的类型:
ngx_pool_t中的cleanup字段管理着一个特殊的链表该链表的每一项都记录着一个特殊的需要释放的资源。对于这个链表中每个节点所包含的资源如何去释放是自说明的。这也就提供了非常大的灵活性。意味着ngx_pool_t不仅仅可以管理内存通过这个机制也可以管理任何需要释放的资源例如关闭文件或者删除文件等等。下面我们看一下这个链表每个节点的类型:
.. code:: c
@ -486,7 +486,7 @@ ngx_pool_t中的cleanup字段管理着一个特殊的链表该链表的每一
:data: 指明了该节点所对应的资源。
:handler: 是一个函数指针指向一个可以释放data所对应资源的函数。该函数只有一个参数就是data。
:handler: 是一个函数指针指向一个可以释放data所对应资源的函数。该函数只有一个参数就是data。
:next: 指向该链表中下一个元素。
@ -548,7 +548,7 @@ ngx_array_t是nginx内部使用的数组结构。nginx的数组结构在存储
创建一个新的数组对象,并返回这个对象。
:p: 数组分配内存使用的内存池;
:n: 数组的初始容量大小,即可以在不扩容的情况下最多可以容纳的元素个数。
:n: 数组的初始容量大小,即在不扩容的情况下最多可以容纳的元素个数。
:size: 单个元素的大小,单位是字节。
@ -590,14 +590,14 @@ ngx_array_t是nginx内部使用的数组结构。nginx的数组结构在存储
ngx_hash_t(100%)
~~~~~~~~~~~~~~~~~~
ngx_hash_t是nginx自己的hash表的实现。定义和实现位于src/core/ngx_hash.h|c中。ngx_hash_t的实现也与数据结构教书上所描述的hash表的实现是大同小异。对于常用的解决冲突的方法有线性探测二次探测和开链法等。ngx_hash_t使用的是最常用的一种也就是开链法这也是STL中的hash表使用的方法。
ngx_hash_t是nginx自己的hash表的实现。定义和实现位于src/core/ngx_hash.h|c中。ngx_hash_t的实现也与数据结构教书上所描述的hash表的实现是大同小异。对于常用的解决冲突的方法有线性探测二次探测和开链法等。ngx_hash_t使用的是最常用的一种也就是开链法这也是STL中的hash表使用的方法。
但是ngx_hash_t的实现又有其几个显著的特点:
1. ngx_hash_t不像其他的hash表的实现可以插入删除元素它只能一次初始化就构建起整个hash表以后既不能再删除也不能在插入元素了。
2. ngx_hash_t的开链并不是真的开了一个链表实际上是开了一段连续的存储空间几乎可以看做是一个数组。这是因为ngx_hash_t在初始化的时候会经历一次预计算的过程提前把每个桶里面会有多少元素放进去给计算出来这样就提前知道每个桶的大小了。那么就不需要使用链表一段连续的存储空间就足够了。这也从一定程度上节省了内存的使用。
从上面的描述,我们可以看出来,实际上ngx_hash_t的使用是非常简单。就两步,首先是初始化,然后就可以在里面进行查找了。下面我们详细来看一下。
从上面的描述,我们可以看出来,这个值越大,越造成内存的浪费。就两步,首先是初始化,然后就可以在里面进行查找了。下面我们详细来看一下。
ngx_hash_t的初始化。
@ -628,7 +628,7 @@ ngx_hash_t的初始化。
:key: 指向从字符串生成hash值的hash函数。nginx的源代码中提供了默认的实现函数ngx_hash_key_lc。
:max_size: hash表中的桶的个数。该字段越大元素存储时冲突的可能性越小每个桶中存储的元素会更少则查询起来的速度更快。当然这个值越大越造成内存的浪费(实际上也浪费不了多少)。
:max_size: hash表中的桶的个数。该字段越大元素存储时冲突的可能性越小每个桶中存储的元素会更少则查询起来的速度更快。当然这个值越大越造成内存的浪费也越大(实际上也浪费不了多少)。
:bucket_size: 每个桶的最大限制大小单位是字节。如果在初始化一个hash表的时候发现某个桶里面无法存的下所有属于该桶的元素则hash表初始化失败。
@ -736,7 +736,7 @@ ngx_hash_combined_t(100%)
nginx提供该类型的作用在于提供一个方便的容器包含三个类型的hash表当有包含通配符的和不包含通配符的一组key构建hash表以后以一种方便的方式来查询你不需要再考虑一个key到底是应该到哪个类型的hash表里去查了。
构造这样一组合hash表的时候首先定义一个该类型的变量分别构造其包含的三个子hash表即可。
构造这样一组合hash表的时候首先定义一个该类型的变量分别构造其包含的三个子hash表即可。
对于该类型hash表的查询nginx提供了一个方便的函数ngx_hash_find_combined。
@ -947,9 +947,9 @@ ngx_buf_t(99%)
:temporary: 为1时表示该buf所包含的内容是在一个用户创建的内存块中并且可以被在filter处理的过程中进行变更而不会造成问题。
:memory: 为1时表示该buf所包含的内容是在内存中但是这些内容不能被进行处理的filter进行变更。
:memory: 为1时表示该buf所包含的内容是在内存中但是这些内容不能被进行处理的filter进行变更。
:mmap: 为1时表示该buf所包含的内容是在内存中, 是通过mmap使用内存映射从文件中映射到内存中的这些内容不能被进行处理的filter进行变更。
:mmap: 为1时表示该buf所包含的内容是在内存中, 是通过mmap使用内存映射从文件中映射到内存中的这些内容不能被进行处理的filter进行变更。
:recycled: 可以回收的。也就是这个buf是可以被释放的。这个字段通常是配合shadow字段一起使用的对于使用ngx_create_temp_buf 函数创建的buf并且是另外一个buf的shadow那么可以使用这个字段来标示这个buf是可以被释放的。
@ -1119,7 +1119,7 @@ ngx_list_t顾名思义看起来好像是一个list的数据结构。这样的
那么什么时候会出现已经有了ngx_list_t类型的对象而其首节点存放元素的内存尚未分配的情况呢那就是这个ngx_list_t类型的变量并不是通过调用ngx_list_create函数创建的。例如如果某个结构体的一个成员变量是ngx_list_t类型的那么当这个结构体类型的对象被创建出来的时候这个成员变量也被创建出来了但是它的首节点的存放元素的内存并未被分配。
总之如果这个ngx_list_t类型的变量如果不是你通过调用函数ngx_list_create创建的那么就必须调用此函数去初始否则你往这个list里追加元素就可能引发不可预知的行为亦或程序会崩溃!
总之如果这个ngx_list_t类型的变量如果不是你通过调用函数ngx_list_create创建的那么就必须调用此函数去初始否则你往这个list里追加元素就可能引发不可预知的行为亦或程序会崩溃!
@ -1413,7 +1413,7 @@ nginx的模块根据其功能基本上可以分为以下几种类型
:output filter: 也称为filter模块主要是负责对输出的内容进行处理可以对输出进行修改。例如可以实现对输出的所有html页面增加预定义的footbar一类的工作或者对输出的图片的URL进行替换之类的工作。
:upstream: upstream模块实现反向代理的功能将真正的请求转发到后端服务器上并从后端服务器上读取响应发回客户端。upstream模块是一种特殊的handler只不过响应内容不是真正自己产生的,而是从后端服务器上读取的。
:upstream: upstream模块实现反向代理的功能将真正的请求转发到后端服务器上并从后端服务器上读取响应发回客户端。upstream模块是一种特殊的handler只不过响应内容不是真正自己产生的,而是从后端服务器上读取的。
:load-balancer: 负载均衡模块,实现特定的算法,在众多的后端服务器中,选择一个服务器出来作为某个请求的转发服务器。
@ -1486,7 +1486,7 @@ worker进程中ngx_worker_process_cycle()函数就是这个无限循环的处
如果一个request对应的location并没有直接有配置的content handler那么nginx依次尝试:
#) 如果一个location里面有配置 random_index on那么随机选择一个文件发送给客户端。
#) 如果一个location里面有配置 index指令那么发送index指令指的文件,给客户端。
#) 如果一个location里面有配置 index指令那么发送index指令指的文件,给客户端。
#) 如果一个location里面有配置 autoindex on那么就发送请求地址对应的服务端路径下的文件列表给客户端。
#) 如果这个request对应的location上有设置gzip_static on那么就查找是否有对应的.gz文件存在有的话就发送这个给客户端客户端支持gzip的情况下
#) 请求的URI如果对应一个静态文件static module就发送静态文件的内容到客户端。