微信公众号:郑尔多斯
关注可了解更多的Nginx知识。任何问题或建议,请公众号留言;
关注公众号,有趣有内涵的文章第一时间送达!
上集回顾
上集介绍到了ngx_http_init_listening()
,本篇文章继续介绍该函数,该函数的主要功能就是创建listening的端口信息。
ngx_create_listening
先介绍这个方法,这个方法主要是创建ngx_listening_t
结构体,这个结构体代表了一个监听端口的信息。
我们看一下ngx_create_listening
源码,如下,我们删除了我们例子用不到的代码,比如错误判断,以及不会被执行的if-else分支等。
1ngx_listening_t *
2ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen)
3{
4 size_t len;
5 ngx_listening_t *ls;
6 struct sockaddr *sa;
7 u_char text[NGX_SOCKADDR_STRLEN];
8 //向全局cycle的listening字段中增加元素,
9 // 该字段保存了所有的监听端口的信息
10 ls = ngx_array_push(&cf->cycle->listening);
11
12 ngx_memzero(ls, sizeof(ngx_listening_t));
13
14 sa = ngx_palloc(cf->pool, socklen);
15 // 结合上篇文章中的图片来看这部分内容
16 ngx_memcpy(sa, sockaddr, socklen);
17
18 ls->sockaddr = sa;
19 ls->socklen = socklen;
20
21 len = ngx_sock_ntop(sa, socklen, text, NGX_SOCKADDR_STRLEN, 1);
22 ls->addr_text.len = len;
23
24 switch (ls->sockaddr->sa_family) {
25
26 case AF_INET:
27 ls->addr_text_max_len = NGX_INET_ADDRSTRLEN;
28 break;
29 }
30
31 ls->addr_text.data = ngx_pnalloc(cf->pool, len);
32 if (ls->addr_text.data == NULL) {
33 return NULL;
34 }
35
36 ngx_memcpy(ls->addr_text.data, text, len);
37
38 ls->fd = (ngx_socket_t) -1;
39 ls->type = SOCK_STREAM;
40
41 ls->backlog = NGX_LISTEN_BACKLOG;
42 ls->rcvbuf = -1;
43 ls->sndbuf = -1;
44
45#if (NGX_HAVE_SETFIB)
46 ls->setfib = -1;
47#endif
48
49#if (NGX_HAVE_TCP_FASTOPEN)
50 ls->fastopen = -1;
51#endif
52
53 return ls;
54}
复制代码
经过ngx_create_listening()
处理之后,返回一个ngx_listening_t
结构体,然后会经过ngx_http_add_listening()
处理,ngx_http_add_listening()
非常简单,就是简单的赋值,经过ngx_http_add_listening()
处理之后的内存布局如下:
ngx_http_init_listening
下面介绍一下ngx_http_init_listening()
函数,顾名思义,这个函数就是初始化listeng
结构体,源码如下,同样的,我们删除了对于我们现在的例子不会执行的代码:
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 = port->addrs.nelts;
11
12 /*
13 * If there is a binding to an "*:port" then we need to bind() to
14 * the "*:port" only and ignore other implicit bindings. The bindings
15 * have been already sorted: explicit bindings are on the start, then
16 * implicit bindings go, and wildcard binding is in the end.
17 */
18
19 if (addr[last - 1].opt.wildcard) {
20 addr[last - 1].opt.bind = 1;
21 bind_wildcard = 1;
22
23 } else {
24 bind_wildcard = 0;
25 }
26
27 i = 0;
28
29 while (i < last) {
30
31 if (bind_wildcard && !addr[i].opt.bind) {
32 i++;
33 continue;
34 }
35
36 ls = ngx_http_add_listening(cf, &addr[i]);
37 if (ls == NULL) {
38 return NGX_ERROR;
39 }
40
41 hport = ngx_pcalloc(cf->pool, sizeof(ngx_http_port_t));
42 if (hport == NULL) {
43 return NGX_ERROR;
44 }
45
46 ls->servers = hport;
47
48 hport->naddrs = i + 1;
49
50 switch (ls->sockaddr->sa_family) {
51 default: /* AF_INET */
52 if (ngx_http_add_addrs(cf, hport, addr) != NGX_OK) {
53 return NGX_ERROR;
54 }
55 break;
56 }
57
58 if (ngx_clone_listening(cf, ls) != NGX_OK) {
59 return NGX_ERROR;
60 }
61
62 addr++;
63 last--;
64 }
65
66 return NGX_OK;
67}
复制代码
从代码中可以看出来,这个函数的执行步骤如下:
- 调用
ngx_http_add_listening()
生成一个监听listening结构体- 调用
ngx_http_add_addrs()
来初始化ngx_http_port
结构体- 调用
ngx_clone_listening()
来完成其他工作
ngx_http_add_addrs()
源码如下:
1static ngx_int_t
2ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport,
3 ngx_http_conf_addr_t *addr)
4{
5 ngx_uint_t i;
6 ngx_http_in_addr_t *addrs;
7 struct sockaddr_in *sin;
8 ngx_http_virtual_names_t *vn;
9
10 hport->addrs = ngx_pcalloc(cf->pool,
11 hport->naddrs * sizeof(ngx_http_in_addr_t));
12 if (hport->addrs == NULL) {
13 return NGX_ERROR;
14 }
15
16 addrs = hport->addrs;
17
18 for (i = 0; i < hport->naddrs; i++) {
19
20 sin = &addr[i].opt.sockaddr.sockaddr_in;
21 addrs[i].addr = sin->sin_addr.s_addr;
22 addrs[i].conf.default_server = addr[i].default_server;
23#if (NGX_HTTP_SSL)
24 addrs[i].conf.ssl = addr[i].opt.ssl;
25#endif
26#if (NGX_HTTP_V2)
27 addrs[i].conf.http2 = addr[i].opt.http2;
28#endif
29 addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol;
30
31 if (addr[i].hash.buckets == NULL
32 && (addr[i].wc_head == NULL
33 || addr[i].wc_head->hash.buckets == NULL)
34 && (addr[i].wc_tail == NULL
35 || addr[i].wc_tail->hash.buckets == NULL)
36#if (NGX_PCRE)
37 && addr[i].nregex == 0
38#endif
39 )
40 {
41 continue;
42 }
43
44 vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t));
45 if (vn == NULL) {
46 return NGX_ERROR;
47 }
48
49 addrs[i].conf.virtual_names = vn;
50
51 vn->names.hash = addr[i].hash;
52 vn->names.wc_head = addr[i].wc_head;
53 vn->names.wc_tail = addr[i].wc_tail;
54#if (NGX_PCRE)
55 vn->nregex = addr[i].nregex;
56 vn->regex = addr[i].regex;
57#endif
58 }
59
60 return NGX_OK;
61}
复制代码
经过上面的代码之后,内存布局如下:
下面的 ngx_clone_listening()
函数并没有执行,所以最终形成的listening结构体就是这样的。到这里ngx_http_optimize_servers()
就执行完毕了。
喜欢本文的朋友们,欢迎长按下图关注订阅号郑尔多斯,更多精彩内容第一时间送达