初始化监听端口

栏目: 服务器 · Nginx · 发布时间: 6年前

内容简介:微信公众号:关注可了解更多的关注公众号,有趣有内涵的文章第一时间送达!上文介绍了

微信公众号:关注可了解更多的 Nginx 知识。任何问题或建议,请公众号留言;

关注公众号,有趣有内涵的文章第一时间送达!

初始化监听端口

前言

上文介绍了 ngx_http_optimize_servers() 函数的一部分内容,下面继续介绍剩下的重头戏。

初始化端口

1for (p = 0; p < ports->nelts; p++) {
2// 前面的内容已经介绍完了
3        if (ngx_http_init_listening(cf, &port[p]) != NGX_OK) {
4            return NGX_ERROR;
5        }
6}
复制代码

源码分析

下面我们详细介绍 ngx_http_init_listening() 函数,源码如下:

 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 // addr 是排过序的,放在最前面的是需要bind的
19    // addr 数组最后一个元素是宽绑定。即:*:port
20    // 就是监听最前面的元素的端口地址和最后一个元素的端口。
21    if (addr[last - 1].opt.wildcard) {
22        addr[last - 1].opt.bind = 1;
23        bind_wildcard = 1;
24
25    } else {
26        bind_wildcard = 0;
27    }
28
29    i = 0;
30
31    while (i < last) {
32
33        if (bind_wildcard && !addr[i].opt.bind) {
34        // 仔细分析一下,i的值就是那些没有显式的指定bind,将要被包含在wildcard中addr的数量
35// 因为 排序 之后的bind在最前面,所以当出现addr[i].opt.bind=0开始,那么后面的addr.opt.bind都为0,
36// 因为这是排序之后的数组。最后的一个元素的addr.opt.bind被nginx设置为了1,参考上面的代码
37            i++;
38            continue;
39        }
40 // 如果能执行到这里,那么有两个条件 
41// ① bind_wildcard=0,即不存在类似 listen *:80 的这种wildcard情况
42// ② bind_wildcard = 1, 即存在wildcard,但是当前的listen指令显式的指定了bind属性
43        ls = ngx_http_add_listening(cf, &addr[i]);
44
45        hport = ngx_pcalloc(cf->pool, sizeof(ngx_http_port_t));
46
47        ls->servers = hport;
48
49        if (i == last - 1) {
50            hport->naddrs = last;
51
52        } else {
53            hport->naddrs = 1;
54            i = 0;
55        }
56
57        switch (ls->sockaddr->sa_family) {
58        default: /* AF_INET */
59            if (ngx_http_add_addrs(cf, hport, addr) != NGX_OK) {
60                return NGX_ERROR;
61            }
62            break;
63        }
64
65        addr++;
66        last--;
67    }
68
69    return NGX_OK;
70}
复制代码

监听端口

上面的源码中有一个非常重要的函数 ngx_http_add_listening() ,这个函数实现了对端口的监听。

 1static ngx_listening_t *
 2ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr)
 3{
 4    ngx_listening_t           *ls;
 5    ngx_http_core_loc_conf_t  *clcf;
 6    ngx_http_core_srv_conf_t  *cscf;
 7// 创建一个新的ngx_listening_t结构体,表示监听的端口
 8    ls = ngx_create_listening(cf, &addr->opt.u.sockaddr, addr->opt.socklen);
 9
10    ls->addr_ntop = 1;
11//下面的一行代码很重要。在accept成功之后会调用ls->handler函数
12    ls->handler = ngx_http_init_connection;
13
14    cscf = addr->default_server;
15    ls->pool_size = cscf->connection_pool_size;
16    ls->post_accept_timeout = cscf->client_header_timeout;
17
18    clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index];
19
20    ls->logp = clcf->error_log;
21    ls->log.data = &ls->addr_text;
22    ls->log.handler = ngx_accept_log_error;
23
24    ls->backlog = addr->opt.backlog;
25    ls->rcvbuf = addr->opt.rcvbuf;
26    ls->sndbuf = addr->opt.sndbuf;
27
28#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
29    ls->accept_filter = addr->opt.accept_filter;
30#endif
31
32#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
33    ls->deferred_accept = addr->opt.deferred_accept;
34#endif
35
36#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
37    ls->ipv6only = addr->opt.ipv6only;
38#endif
39
40#if (NGX_HAVE_SETFIB)
41    ls->setfib = addr->opt.setfib;
42#endif
43
44    return ls;
45}
复制代码

上面的函数又调用了 ngx_create_listening() ,源码如下:

 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    ls = ngx_array_push(&cf->cycle->listening);
10
11    ngx_memzero(ls, sizeof(ngx_listening_t));
12// ngx_listening_t结构的sockaddr表示的是监听的端口的结构
13    sa = ngx_palloc(cf->pool, socklen);
14    ngx_memcpy(sa, sockaddr, socklen);
15    ls->sockaddr = sa;
16    ls->socklen = socklen;
17
18//ngx_listening_t结构的addr_text就是监听的地址信息的字符串,包括端口
19    len = ngx_sock_ntop(sa, text, NGX_SOCKADDR_STRLEN, 1);
20    ls->addr_text.len = len;
21
22    switch (ls->sockaddr->sa_family) {
23
24    case AF_INET:
25         ls->addr_text_max_len = NGX_INET_ADDRSTRLEN;
26         break;
27     }
28// ngx_listening_t结构的addr_text就是监听的地址信息的字符串,包括端口
29    ls->addr_text.data = ngx_pnalloc(cf->pool, len);
30    ngx_memcpy(ls->addr_text.data, text, len);
31
32    ls->fd = (ngx_socket_t) -1;
33    ls->type = SOCK_STREAM;// 表示监听的TCP
34
35    ls->backlog = NGX_LISTEN_BACKLOG;
36    ls->rcvbuf = -1;
37    ls->sndbuf = -1;
38
39#if (NGX_HAVE_SETFIB)
40    ls->setfib = -1;
41#endif
42
43    return ls;
44}
复制代码

上面还牵涉到一个比较简单的函数 ngx_sock_ntop() ,这个函数的功能很简单,就是把sockaddr格式的ip地址转换为一个字符串

 1/*
 2 *参数的含义:
 3 * sa : 要转换为字符串的ip地址
 4 * text: 保存转换之后的字符串
 5 * len: sa参数的长度
 6 * port: 0或者1,表示是否将端口也转换为字符串,如果为0则不转换,若为1则转换
 7 * 返回值:转换的字符串的长度
 8*/
 9size_t
10ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port)
11{
12    u_char               *p;
13    struct sockaddr_in   *sin;
14
15    switch (sa->sa_family) {
16
17    case AF_INET:
18
19        sin = (struct sockaddr_in *) sa;
20        p = (u_char *) &sin->sin_addr;
21
22        if (port) {
23            p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud:%d",
24                             p[0], p[1], p[2], p[3], ntohs(sin->sin_port));
25        } else {
26            p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud",
27                             p[0], p[1], p[2], p[3]);
28        }
29
30        return (p - text);
31    }
32}
复制代码

数据结构

本文牵涉到的数据结构比较多,整理如下:

 1typedef struct {
 2    /* ngx_http_in_addr_t or ngx_http_in6_addr_t */
 3    void        *addrs;  // ngx_http_in_addr_t 数组
 4    ngx_uint_t  naddrs; // 表示 addrs 数组元素的个数
 5} ngx_http_port_t;
 6
 7
 8typedef struct {
 9    in_addr_t                  addr; // 当前监听的地址
10    ngx_http_addr_conf_t       conf; //参考下面的数据结构
11} ngx_http_in_addr_t;
12
13
14typedef struct {
15    /* the default server configuration for this address:port */
16    ngx_http_core_srv_conf_t  *default_server; // 当前address:port的default server
17    ngx_http_virtual_names_t  *virtual_names; // 参考下面的数据结构
18
19#if (NGX_HTTP_SSL)
20    ngx_uint_t                 ssl;   /* unsigned  ssl:1; */ // 表示listen指令是否使用了ssl
21#endif
22} ngx_http_addr_conf_t;
23
24
25typedef struct {
26// 参考下面的数据结构
27// name的hash指向address:port的hash
28// name的wc_head指向address:port的wc_head
29// name的wc_tail指向address:port的wc_tail
30// 也就是说把 address:port 的 hash,wc_head,wc_tail组合成一个ngx_hash_combined_t类型的数据结构,为后面做准备.
31// 因为后面使用到的都是 ngx_http_port_t 结构体,不再使用address:port对应的ngx_http_conf_addr_t结构体
32     ngx_hash_combined_t              names; 
33
34     ngx_uint_t                       nregex;
35     ngx_http_server_name_t          *regex;
36} ngx_http_virtual_names_t;
37
38
39typedef struct {
40    ngx_hash_t            hash;
41    ngx_hash_wildcard_t  *wc_head;
42    ngx_hash_wildcard_t  *wc_tail;
43} ngx_hash_combined_t;
复制代码

喜欢本文的朋友们,欢迎长按下图关注订阅号郑尔多斯,更多精彩内容第一时间送达

初始化监听端口
郑尔多斯

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Data Mining

Web Data Mining

Bing Liu / Springer / 2011-6-26 / CAD 61.50

Web mining aims to discover useful information and knowledge from Web hyperlinks, page contents, and usage data. Although Web mining uses many conventional data mining techniques, it is not purely an ......一起来看看 《Web Data Mining》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具