微信公眾號:鄭爾多斯
關注可瞭解更多的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()
就執行完畢了。
喜歡本文的朋友們,歡迎長按下圖關注訂閱號鄭爾多斯,更多精彩內容第一時間送達