微信公众号:郑尔多斯
关注可了解更多的Nginx知识。任何问题或建议,请公众号留言;
关注公众号,有趣有内涵的文章第一时间送达!nginx
本篇文章主要是分析配置文件解析完毕以后对listen
的进一步优化。这一部分主要完成了端口的初始化以及打开操做。数组
在ngx_http_block()
中有下面的一部分代码,以下:微信
1 /* optimize the lists of ports, addresses and server names */
2
3if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) {
4 return NGX_CONF_ERROR;
5}
复制代码
从上面的代码注释中能够看出来,ngx_http_optimize_servers()
函数的做用就是对咱们监听的端口,address以及server name进行优化处理的,下面咱们结合本身的例子分析一下这个方法。
先把咱们解析完http
指令以后的内存结构图放出来:
app
先看一下源码,以下:函数
1static ngx_int_t
2ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, ngx_array_t *ports)
3{
4 ngx_uint_t p, a;
5 ngx_http_conf_port_t *port;
6 ngx_http_conf_addr_t *addr;
7
8 if (ports == NULL) {
9 return NGX_OK;
10 }
11
12 port = ports->elts;
13//遍历全部的ports数组
14 for (p = 0; p < ports->nelts; p++) {
15// 对每一个port下的全部addr进行排序
16 ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts,
17 sizeof(ngx_http_conf_addr_t), ngx_http_cmp_conf_addrs);
18
19 /*
20 * check whether all name-based servers have the same
21 * configuration as a default server for given address:port
22 */
23
24 addr = port[p].addrs.elts;
25 for (a = 0; a < port[p].addrs.nelts; a++) {
26
27 if (addr[a].servers.nelts > 1
28#if (NGX_PCRE)
29 || addr[a].default_server->captures
30#endif
31 )
32 {
33 if (ngx_http_server_names(cf, cmcf, &addr[a]) != NGX_OK) {
34 return NGX_ERROR;
35 }
36 }
37 }
38
39 if (ngx_http_init_listening(cf, &port[p]) != NGX_OK) {
40 return NGX_ERROR;
41 }
42 }
43
44 return NGX_OK;
45}
复制代码
从上面的代码中能够看到,nginx会遍历全部的port,而后对每一个遍历到的port调用ngx_sort()
进行排序,使用的排序函数为ngx_http_cmp_conf_addrs()
,该函数以下:优化
1ngx_http_cmp_conf_addrs(const void *one, const void *two)
2{
3 ngx_http_conf_addr_t *first, *second;
4
5 first = (ngx_http_conf_addr_t *) one;
6 second = (ngx_http_conf_addr_t *) two;
7
8 if (first->opt.wildcard) {
9 /* a wildcard address must be the last resort, shift it to the end */
10 return 1;
11 }
12
13 if (second->opt.wildcard) {
14 /* a wildcard address must be the last resort, shift it to the end */
15 return -1;
16 }
17
18 if (first->opt.bind && !second->opt.bind) {
19 /* shift explicit bind()ed addresses to the start */
20 return -1;
21 }
22
23 if (!first->opt.bind && second->opt.bind) {
24 /* shift explicit bind()ed addresses to the start */
25 return 1;
26 }
27
28 /* do not sort by default */
29
30 return 0;
31}
复制代码
从代码中能够看到排序规则:ui
- 若是first addr是wildcard,那么这个addr排在后面second的后面,这一句就说明wildcard 属性要排在全部的地址的后面。
- 若是first addr不是wildcard,可是second 是wildcard,那么first排在second的前面,也就是说wildcard类型的要排在 非wildcard后面
- 若是 first和second 都不是wildcard,可是first有bind属性,而second没有bind属性,那么first排在second的前面,这个规则说明bind属性要排在非bind的前面。
- 若是first和second都不是wildcard,可是first没有bind属性,而second有bind属性,那么frist排在second的后面,也是为了说明bind要排在前面。
- 其余状况的排序规则不变
上图是排序以后的样式,不过因为咱们只有一个addr,因此这里并无这么麻烦。spa
咱们真正要关心的是这个函数,它对我么监听的端口进行了处理:code
1static ngx_int_t
2ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port)
3{
4 ngx_uint_t i, last, bind_wildcard;
5 ngx_listening_t *ls;
6 ngx_http_port_t *hport;
7 ngx_http_conf_addr_t *addr;
8
9 addr = port->addrs.elts;
10// 在本例子中last = 1
11 last = port->addrs.nelts;
12
13 /*
14 * If there is a binding to an "*:port" then we need to bind() to
15 * the "*:port" only and ignore other implicit bindings. The bindings
16 * have been already sorted: explicit bindings are on the start, then
17 * implicit bindings go, and wildcard binding is in the end.
18 */
19
20 if (addr[last - 1].opt.wildcard) {
21 addr[last - 1].opt.bind = 1;
22 bind_wildcard = 1;
23
24 } else {
25 bind_wildcard = 0;
26 }
27
28 i = 0;
29
30 while (i < last) {
31
32 if (bind_wildcard && !addr[i].opt.bind) {
33 i++;
34 continue;
35 }
36
37 ls = ngx_http_add_listening(cf, &addr[i]);
38 if (ls == NULL) {
39 return NGX_ERROR;
40 }
41
42 hport = ngx_pcalloc(cf->pool, sizeof(ngx_http_port_t));
43 if (hport == NULL) {
44 return NGX_ERROR;
45 }
46
47 ls->servers = hport;
48
49 hport->naddrs = i + 1;
50
51 switch (ls->sockaddr->sa_family) {
52
53#if (NGX_HAVE_INET6)
54 case AF_INET6:
55 if (ngx_http_add_addrs6(cf, hport, addr) != NGX_OK) {
56 return NGX_ERROR;
57 }
58 break;
59#endif
60 default: /* AF_INET */
61 if (ngx_http_add_addrs(cf, hport, addr) != NGX_OK) {
62 return NGX_ERROR;
63 }
64 break;
65 }
66
67 if (ngx_clone_listening(cf, ls) != NGX_OK) {
68 return NGX_ERROR;
69 }
70
71 addr++;
72 last--;
73 }
74
75 return NGX_OK;
76}
复制代码
预知后事如何,且听下文分解orm
喜欢本文的朋友们,欢迎长按下图关注订阅号郑尔多斯,更多精彩内容第一时间送达