zoukankan      html  css  js  c++  java
  • 初始化监听端口

    微信公众号:郑尔多斯
    关注可了解更多的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 数组元素的个数
    5ngx_http_port_t;
    6
    7
    8typedef struct {
    9    in_addr_t                  addr; // 当前监听的地址
    10    ngx_http_addr_conf_t       conf; //参考下面的数据结构
    11ngx_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
    22ngx_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;
    36ngx_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;
    43ngx_hash_combined_t;

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

    郑尔多斯郑尔多斯
  • 相关阅读:
    js在线压缩网址
    java 排序
    java访问权限(子类继承父类的方法)
    重庆大学第八届编程大赛初赛1、2题目
    重庆大学oj系统——习题
    种花问题(Can Place Flowers)——两朵花不能相邻
    TFIDF计算
    python自定义聚合函数,merge与transform的区别
    AFM模型 pytorch示例代码
    python计算信息增益
  • 原文地址:https://www.cnblogs.com/zhengerduosi/p/10441579.html
Copyright © 2011-2022 走看看