IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    nginx模块开发(42)—网络初始化之listen(上)

    cjhust发表于 2015-01-13 14:31:55
    love 0

    1、知识百科

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解。与网络有关的配置命令主要有两个:listen和sever_name。listen命令设置nginx监听地址,对于IP协议,这个地址就是address和port,对于UNIX域套接字协议,这个地址就是path,一条listen指令只能指定一个address或者port,address也可以是主机名,比如:

    listen 127.0.0.1:8000;

    listen 127.0.0.1;

    listen 8000;

    listen *:8000;

    listen localhost:8000;

    listen [::]:8000;

    listen [fe80::1];

    listen unix:/var/run/nginx.sock;

    server_name指令列出虚拟主机的所有主机名,如server_name example.com *.example.com www.example.*,用空格分割。

    2、数据结构

    clip_image002

    clip_image002[4]

    ngx_http_conf_port_t(ngx_http_core_listen入口)

    typedef struct {

    ngx_int_t family;

    in_port_t port;

    ngx_array_t addrs; /* array of ngx_http_conf_addr_t */

    } ngx_http_conf_port_t;

    ngx_http_conf_addr_t

    typedef struct {

    ngx_http_listen_opt_t opt;

    ngx_hash_t hash;

    ngx_hash_wildcard_t *wc_head;

    ngx_hash_wildcard_t *wc_tail;

    ngx_http_core_srv_conf_t *default_server;

    ngx_array_t servers; /* array of ngx_http_core_srv_conf_t */

    } ngx_http_conf_addr_t;

    ngx_http_core_srv_conf_t

    typedef struct {

    /* array of the ngx_http_server_name_t, "server_name" directive */

    ngx_array_t server_names;

    /* server ctx */

    ngx_http_conf_ctx_t *ctx;

    ngx_str_t server_name;

    size_t connection_pool_size;

    size_t request_pool_size;

    size_t client_header_buffer_size;

    ngx_bufs_t large_client_header_buffers;

    ngx_msec_t client_header_timeout;

    ngx_flag_t ignore_invalid_headers;

    ngx_flag_t merge_slashes;

    ngx_flag_t underscores_in_headers;

    unsigned listen:1;

    ngx_http_core_loc_conf_t **named_locations;

    } ngx_http_core_srv_conf_t;

    ngx_http_listen_opt_t(重要)

    typedef struct {

    union {

    struct sockaddr sockaddr;

    struct sockaddr_in sockaddr_in;

    u_char sockaddr_data[NGX_SOCKADDRLEN];

    } u;

    socklen_t socklen;

    unsigned set:1; // bind/backlog/…

    unsigned default_server:1; // default_server

    unsigned bind:1; // bind/backlog/…

    unsigned wildcard:1;

    #if (NGX_HTTP_SSL)

    unsigned ssl:1;

    #endif

    #if (NGX_HTTP_SPDY)

    unsigned spdy:1; // spdy

    #endif

    unsigned so_keepalive:2;

    unsigned proxy_protocol:1; // proxy_protocol

    int backlog; // backlog

    int rcvbuf; // rcvbuf

    int sndbuf; // sndbuf

    。。。

    u_char addr[NGX_SOCKADDR_STRLEN + 1]; // 0.0.0.0:8000

    } ngx_http_listen_opt_t;

    ngx_listening_s(ngx_http_init_connection入口)

    image

    struct ngx_listening_s {

    ngx_socket_t fd;

    struct sockaddr *sockaddr;

    socklen_t socklen; /* size of sockaddr */

    size_t addr_text_max_len;

    ngx_str_t addr_text;

    int type;

    int backlog;

    int rcvbuf;

    int sndbuf;

    ngx_connection_handler_pt handler;

    void *servers; /* array of ngx_http_port_t, for example */

    。。。

    ngx_listening_t *previous;

    ngx_connection_t *connection;

    unsigned open:1;

    unsigned remain:1;

    unsigned ignore:1;

    unsigned bound:1; /* already bound */

    unsigned inherited:1; /* inherited from previous process */

    unsigned nonblocking_accept:1;

    unsigned listen:1;

    unsigned nonblocking:1;

    unsigned shared:1; /* shared between threads or processes */

    unsigned addr_ntop:1;

    unsigned keepalive:2;

    };

    ngx_http_port_t

    typedef struct {

    /* ngx_http_in_addr_t or ngx_http_in6_addr_t */

    void *addrs;

    ngx_uint_t naddrs;

    } ngx_http_port_t;

    ngx_http_in_addr_t

    typedef struct {

    in_addr_t addr;

    ngx_http_addr_conf_t conf;

    } ngx_http_in_addr_t;

    ngx_http_addr_conf_s

    struct ngx_http_addr_conf_s {

    /* the default server configuration for this address:port */

    ngx_http_core_srv_conf_t *default_server;

    ngx_http_virtual_names_t *virtual_names;

    #if (NGX_HTTP_SSL)

    unsigned ssl:1;

    #endif

    #if (NGX_HTTP_SPDY)

    unsigned spdy:1;

    #endif

    unsigned proxy_protocol:1;

    };

    3、源码解析

    clip_image002[6]

    ngx_http_core_server_name

    函数功能:解析server_name指令。

    static char *

    ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)

    {

    ngx_http_core_srv_conf_t *cscf = conf;

    u_char ch;

    ngx_str_t *value;

    ngx_uint_t i;

    ngx_http_server_name_t *sn;

    value = cf->args->elts;

    for (i = 1; i < cf->args->nelts; i++) {

    ch = value[i].data[0];

    if ((ch == '*' && (value[i].len < 3 || value[i].data[1] != '.'))

    || (ch == '.' && value[i].len < 2))

    {

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

    "server name \"%V\" is invalid", &value;[i]);

    return NGX_CONF_ERROR;

    }

    if (ngx_strchr(value[i].data, '/')) {

    ngx_conf_log_error(NGX_LOG_WARN, cf, 0,

    "server name \"%V\" has suspicious symbols",

    &value;[i]);

    }

    sn = ngx_array_push(&cscf->server_names);

    if (sn == NULL) {

    return NGX_CONF_ERROR;

    }

    sn->server = cscf;

    if (ngx_strcasecmp(value[i].data, (u_char *) "$hostname") == 0) {

    sn->name = cf->cycle->hostname;

    } else {

    sn->name = value[i];

    }

    if (value[i].data[0] != '~') {

    ngx_strlow(sn->name.data, sn->name.data, sn->name.len);

    continue;

    }

    。。。

    }

    return NGX_CONF_OK;

    }

    ngx_http_core_listen

    函数功能:解析listen指令。

    static char *

    ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)

    {

    ngx_http_core_srv_conf_t *cscf = conf;

    ngx_str_t *value, size;

    ngx_url_t u;

    ngx_uint_t n;

    ngx_http_listen_opt_t lsopt;

    cscf->listen = 1;

    value = cf->args->elts;

    ngx_memzero(&u;, sizeof(ngx_url_t));

    u.url = value[1];

    u.listen = 1;

    u.default_port = 80;

    //解析listen命令后面的参数,ip:port

    if (ngx_parse_url(cf->pool, &u;) != NGX_OK) {

    if (u.err) {

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

    "%s in \"%V\" of the \"listen\" directive",

    u.err, &u.url;);

    }

    return NGX_CONF_ERROR;

    }

    ngx_memzero(&lsopt;, sizeof(ngx_http_listen_opt_t));

    ngx_memcpy(&lsopt.u.sockaddr;, u.sockaddr, u.socklen);

    lsopt.socklen = u.socklen;

    lsopt.backlog = NGX_LISTEN_BACKLOG;

    lsopt.rcvbuf = -1;

    lsopt.sndbuf = -1;

    lsopt.wildcard = u.wildcard; //listen 80

    (void) ngx_sock_ntop(&lsopt.u.sockaddr;, lsopt.socklen, lsopt.addr,

    NGX_SOCKADDR_STRLEN, 1);

    for (n = 2; n < cf->args->nelts; n++) {

    if (ngx_strcmp(value[n].data, "default_server") == 0

    || ngx_strcmp(value[n].data, "default") == 0)

    {

    lsopt.default_server = 1;

    continue;

    }

    ….

    if (ngx_strncmp(value[n].data, "backlog=", 8) == 0) {

    lsopt.backlog = ngx_atoi(value[n].data + 8, value[n].len - 8);

    lsopt.set = 1;

    lsopt.bind = 1;

    if (lsopt.backlog == NGX_ERROR || lsopt.backlog == 0) {

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

    "invalid backlog \"%V\"", &value;[n]);

    return NGX_CONF_ERROR;

    }

    continue;

    }

    if (ngx_strcmp(value[n].data, "ssl") == 0) {

    #if (NGX_HTTP_SSL)

    lsopt.ssl = 1;

    continue;

    #else

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

    "the \"ssl\" parameter requires "

    "ngx_http_ssl_module");

    return NGX_CONF_ERROR;

    #endif

    }

    if (ngx_strcmp(value[n].data, "spdy") == 0) {

    #if (NGX_HTTP_SPDY)

    lsopt.spdy = 1;

    continue;

    #else

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

    "the \"spdy\" parameter requires "

    "ngx_http_spdy_module");

    return NGX_CONF_ERROR;

    #endif

    }

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

    "invalid parameter \"%V\"", &value;[n]);

    return NGX_CONF_ERROR;

    }

    //将解析到的虚拟主机的地址信息加入到监听列表中

    if (ngx_http_add_listen(cf, cscf, &lsopt;) == NGX_OK) {

    return NGX_CONF_OK;

    }

    return NGX_CONF_ERROR;

    }

    ngx_http_add_listen

    函数功能:以port为粒度,添加addr(即1.1.1.1:80、2.2.2.2:80和80,会放在相同的cmcf->port[i]中)。

    clip_image002[8]

    ngx_int_t

    ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,

    ngx_http_listen_opt_t *lsopt)

    {

    in_port_t p;

    ngx_uint_t i;

    struct sockaddr *sa;

    struct sockaddr_in *sin;

    ngx_http_conf_port_t *port;

    ngx_http_core_main_conf_t *cmcf;

    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

    if (cmcf->ports == NULL) { //全局

    cmcf->ports = ngx_array_create(cf->temp_pool, 2,

    sizeof(ngx_http_conf_port_t));

    if (cmcf->ports == NULL) {

    return NGX_ERROR;

    }

    }

    sa = &lsopt-;>u.sockaddr;

    switch (sa->sa_family) {

    …

    default: /* AF_INET */

    sin = &lsopt-;>u.sockaddr_in;

    p = sin->sin_port;

    break;

    }

    port = cmcf->ports->elts;

    for (i = 0; i < cmcf->ports->nelts; i++) {

    if (p != port[i].port || sa->sa_family != port[i].family) {

    continue;

    }

    //相同的port共用相同的address

    return ngx_http_add_addresses(cf, cscf, &port;[i], lsopt);

    }

    port = ngx_array_push(cmcf->ports);

    if (port == NULL) {

    return NGX_ERROR;

    }

    port->family = sa->sa_family;

    port->port = p;

    port->addrs.elts = NULL;

    return ngx_http_add_address(cf, cscf, port, lsopt);

    }

    ngx_http_add_addresses

    函数功能:相同的port,相同的addr,则ngx_http_add_server(如listen 8080,server_name hello和server_name world),相同的port,不同的addr,则ngx_http_add_address(如listen 1.1.1.1:80和2.2.2.2:80)。

    clip_image002[10]

    nginx模块开发(42)—网络初始化之listen(上) - cjhust - 我一直在努力

    static ngx_int_t

    ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,

    ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)

    {

    u_char *p;

    size_t len, off;

    ngx_uint_t i, default_server;

    struct sockaddr *sa;

    ngx_http_conf_addr_t *addr;

    #if (NGX_HTTP_SSL)

    ngx_uint_t ssl;

    #endif

    #if (NGX_HTTP_SPDY)

    ngx_uint_t spdy;

    #endif

    sa = &lsopt-;>u.sockaddr;

    switch (sa->sa_family) {

    default: /* AF_INET */

    off = offsetof(struct sockaddr_in, sin_addr); // 4

    len = 4;

    break;

    }

    p = lsopt->u.sockaddr_data + off; //u_char

    addr = port->addrs.elts;

    for (i = 0; i < port->addrs.nelts; i++) {

    if (ngx_memcmp(p, addr[i].opt.u.sockaddr_data + off, len) != 0) { //比较sin_addr

    continue;

    }

    //相同的addr:port,不同的server_name

    if (ngx_http_add_server(cf, cscf, &addr;[i]) != NGX_OK) {

    return NGX_ERROR;

    }

    /* preserve default_server bit during listen options overwriting */

    default_server = addr[i].opt.default_server;

    #if (NGX_HTTP_SSL)

    ssl = lsopt->ssl || addr[i].opt.ssl;

    #endif

    #if (NGX_HTTP_SPDY)

    spdy = lsopt->spdy || addr[i].opt.spdy;

    #endif

    if (lsopt->set) {

    if (addr[i].opt.set) {

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

    "duplicate listen options for %s", addr[i].opt.addr);

    return NGX_ERROR;

    }

    addr[i].opt = *lsopt;

    }

    /* check the duplicate "default" server for this address:port */

    if (lsopt->default_server) {

    if (default_server) {

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

    "a duplicate default server for %s", addr[i].opt.addr);

    return NGX_ERROR;

    }

    default_server = 1;

    addr[i].default_server = cscf;

    }

    addr[i].opt.default_server = default_server;

    #if (NGX_HTTP_SSL)

    addr[i].opt.ssl = ssl;

    #endif

    #if (NGX_HTTP_SPDY)

    addr[i].opt.spdy = spdy;

    #endif

    return NGX_OK;

    }

    /* add the address to the addresses list that bound to this port */

    return ngx_http_add_address(cf, cscf, port, lsopt);

    }

    ngx_http_add_address

    static ngx_int_t

    ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,

    ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)

    {

    ngx_http_conf_addr_t *addr;

    if (port->addrs.elts == NULL) {

    if (ngx_array_init(&port-;>addrs, cf->temp_pool, 4,

    sizeof(ngx_http_conf_addr_t))

    != NGX_OK)

    {

    return NGX_ERROR;

    }

    }

    addr = ngx_array_push(&port-;>addrs);

    if (addr == NULL) {

    return NGX_ERROR;

    }

    addr->opt = *lsopt;

    addr->hash.buckets = NULL;

    addr->hash.size = 0;

    addr->wc_head = NULL;

    addr->wc_tail = NULL;

    #if (NGX_PCRE)

    addr->nregex = 0;

    addr->regex = NULL;

    #endif

    addr->default_server = cscf;

    addr->servers.elts = NULL;

    return ngx_http_add_server(cf, cscf, addr);

    }

    ngx_http_add_server

    函数功能:将新的虚拟主机信息加入到这个地址的虚拟主机列表中。

    static ngx_int_t

    ngx_http_add_server(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,

    ngx_http_conf_addr_t *addr)

    {

    ngx_uint_t i;

    ngx_http_core_srv_conf_t **server;

    if (addr->servers.elts == NULL) {

    if (ngx_array_init(&addr-;>servers, cf->temp_pool, 4,

    sizeof(ngx_http_core_srv_conf_t *))

    != NGX_OK)

    {

    return NGX_ERROR;

    }

    } else {

    server = addr->servers.elts;

    for (i = 0; i < addr->servers.nelts; i++) { //相同的server,相同的listen

    if (server[i] == cscf) {

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

    "a duplicate listen %s", addr->opt.addr);

    return NGX_ERROR;

    }

    }

    }

    server = ngx_array_push(&addr-;>servers);

    if (server == NULL) {

    return NGX_ERROR;

    }

    *server = cscf;

    return NGX_OK;

    }

    ngx_http_block->ngx_http_optimize_servers

    image

    函数功能:ngx_http_block的最后一步。

    static ngx_int_t

    ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,

    ngx_array_t *ports)

    {

    ngx_uint_t p, a;

    ngx_http_conf_port_t *port;

    ngx_http_conf_addr_t *addr;

    if (ports == NULL) {

    return NGX_OK;

    }

    port = ports->elts;

    for (p = 0; p < ports->nelts; p++) {

    //比如listen 80和listen 127.0.0.1:80

    //排序原则:通配符如listen 80和listen*:80,会排在最后面,listen 1.1.1.1:80 backlog=512等会排在最前面

    ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts,

    sizeof(ngx_http_conf_addr_t), ngx_http_cmp_conf_addrs);

    addr = port[p].addrs.elts;

    for (a = 0; a < port[p].addrs.nelts; a++) {

    if (addr[a].servers.nelts > 1 //相同的addr:port,不同的server_name

    #if (NGX_PCRE)

    || addr[a].default_server->captures

    #endif

    )

    {

    if (ngx_http_server_names(cf, cmcf, &addr;[a]) != NGX_OK) {

    return NGX_ERROR;

    }

    }

    }

    if (ngx_http_init_listening(cf, &port;[p]) != NGX_OK) { //一个port,一个listening

    return NGX_ERROR;

    }

    }

    return NGX_OK;

    }

    ngx_http_server_names

    函数功能:相同的addr:port的优化处理。

    static ngx_int_t

    ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,

    ngx_http_conf_addr_t *addr)

    {

    ngx_int_t rc;

    ngx_uint_t n, s;

    ngx_hash_init_t hash;

    ngx_hash_keys_arrays_t ha;

    ngx_http_server_name_t *name;

    ngx_http_core_srv_conf_t **cscfp;

    ngx_memzero(&ha;, sizeof(ngx_hash_keys_arrays_t));

    ha.temp_pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log);

    if (ha.temp_pool == NULL) {

    return NGX_ERROR;

    }

    ha.pool = cf->pool;

    if (ngx_hash_keys_array_init(&ha;, NGX_HASH_LARGE) != NGX_OK) {

    goto failed;

    }

    cscfp = addr->servers.elts;

    for (s = 0; s < addr->servers.nelts; s++) {

    name = cscfp[s]->server_names.elts; //一个server可以有多个server_name

    for (n = 0; n < cscfp[s]->server_names.nelts; n++) {

    rc = ngx_hash_add_key(&ha;, &name;[n].name, name[n].server,

    NGX_HASH_WILDCARD_KEY);

    if (rc == NGX_ERROR) {

    return NGX_ERROR;

    }

    if (rc == NGX_DECLINED) {

    ngx_log_error(NGX_LOG_EMERG, cf->log, 0,

    "invalid server name or wildcard \"%V\" on %s",

    &name;[n].name, addr->opt.addr);

    return NGX_ERROR;

    }

    if (rc == NGX_BUSY) {

    ngx_log_error(NGX_LOG_WARN, cf->log, 0,

    "conflicting server name \"%V\" on %s, ignored",

    &name;[n].name, addr->opt.addr);

    }

    }

    }

    hash.key = ngx_hash_key_lc;

    hash.max_size = cmcf->server_names_hash_max_size;

    hash.bucket_size = cmcf->server_names_hash_bucket_size;

    hash.name = "server_names_hash";

    hash.pool = cf->pool;

    if (ha.keys.nelts) { //无通配

    hash.hash = &addr-;>hash;

    hash.temp_pool = NULL;

    if (ngx_hash_init(&hash;, ha.keys.elts, ha.keys.nelts) != NGX_OK) {

    goto failed;

    }

    }

    if (ha.dns_wc_head.nelts) { //前缀通配

    ngx_qsort(ha.dns_wc_head.elts, (size_t) ha.dns_wc_head.nelts,

    sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards);

    hash.hash = NULL;

    hash.temp_pool = ha.temp_pool;

    if (ngx_hash_wildcard_init(&hash;, ha.dns_wc_head.elts,

    ha.dns_wc_head.nelts)

    != NGX_OK)

    {

    goto failed;

    }

    addr->wc_head = (ngx_hash_wildcard_t *) hash.hash;

    }

    if (ha.dns_wc_tail.nelts) { //后缀通配

    ngx_qsort(ha.dns_wc_tail.elts, (size_t) ha.dns_wc_tail.nelts,

    sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards);

    hash.hash = NULL;

    hash.temp_pool = ha.temp_pool;

    if (ngx_hash_wildcard_init(&hash;, ha.dns_wc_tail.elts,

    ha.dns_wc_tail.nelts)

    != NGX_OK)

    {

    goto failed;

    }

    addr->wc_tail = (ngx_hash_wildcard_t *) hash.hash;

    }

    ngx_destroy_pool(ha.temp_pool);

    return NGX_OK;

    failed:

    ngx_destroy_pool(ha.temp_pool);

    return NGX_ERROR;

    }

    ngx_http_cmp_conf_addrs

    static ngx_int_t

    ngx_http_cmp_conf_addrs(const void *one, const void *two)

    {

    ngx_http_conf_addr_t *first, *second;

    first = (ngx_http_conf_addr_t *) one;

    second = (ngx_http_conf_addr_t *) two;

    //通配符必须是最后一个,返回1,则表示要交换顺序

    if (first->opt.wildcard) {

    /* a wildcard address must be the last resort, shift it to the end */

    return 1;

    }

    //通配符必须是最后一个,不需要换位置

    if (second->opt.wildcard) {

    /* a wildcard address must be the last resort, shift it to the end */

    return -1;

    }

    //设置如backlog的,需要放在前面

    if (first->opt.bind && !second->opt.bind) {

    /* shift explicit bind()ed addresses to the start */

    return -1;

    }

    //设置如backlog的,需要放在前面

    if (!first->opt.bind && second->opt.bind) {

    /* shift explicit bind()ed addresses to the start */

    return 1;

    }

    /* do not sort by default */

    return 0;

    }

    ngx_http_init_listening(重要)

    clip_image002[14]

    函数功能:用新的结构(cycle-> listening)存储这些关系。

    static ngx_int_t

    ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port)

    {

    ngx_uint_t i, last, bind_wildcard;

    ngx_listening_t *ls;

    ngx_http_port_t *hport;

    ngx_http_conf_addr_t *addr;

    addr = port->addrs.elts;

    last = port->addrs.nelts; //相同的port,不同的addr个数

    if (addr[last - 1].opt.wildcard) { //通配符需要放在最后一个,设置backlog的需要放在前面

    addr[last - 1].opt.bind = 1;

    bind_wildcard = 1;

    } else {

    bind_wildcard = 0;

    }

    i = 0;

    while (i < last) {

    if (bind_wildcard && !addr[i].opt.bind) {

    i++;

    continue;

    }

    //这个函数里面将会创建,并且初始化listen结构,这个listen已经存放在cycle结构的listen数组中

    ls = ngx_http_add_listening(cf, &addr;[i]); //port->addrs.elts

    if (ls == NULL) {

    return NGX_ERROR;

    }

    hport = ngx_pcalloc(cf->pool, sizeof(ngx_http_port_t));

    if (hport == NULL) {

    return NGX_ERROR;

    }

    ls->servers = hport;

    if (i == last - 1) {

    hport->naddrs = last; //将*:port和没有显式bind的address:port放在同一个listen中,如listen 80和listen 1.1.1.1:80可以放在一个listening中

    } else {

    hport->naddrs = 1;

    //重新赋值为0,因为最前面可能是listen 2.2.2.2:80 backlog=512这样的

    i = 0;

    }

    switch (ls->sockaddr->sa_family) {

    default: /* AF_INET */

    if (ngx_http_add_addrs(cf, hport, addr) != NGX_OK) {

    return NGX_ERROR;

    }

    break;

    }

    addr++;

    last--;

    }

    return NGX_OK;

    }



沪ICP备19023445号-2号
友情链接