listen command
nginx is a high-performance http server, and network processing is its core. Understanding network initialization will help deepen your understanding of nginx network processing. . There are two main network-related configuration commands: listen and sever_name. The listen command sets the nginx listening address. For the IP protocol, this address is the address and port. For the Unix domain socket protocol, this address is the path. A listen command can only specify one address or port. The address can also be the host name
Starting from this article, we analyze the parsing process of the listen instruction. The configuration of the listen instruction is as follows: From the nginx.org manual, we can get the usage of listen:
listen address[:port] [default_server] [setfib=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [ssl] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
A listen instruction The parameters carried are very complex. However, we generally pay little attention to those less commonly used parameters. The following are some commonly used configuration methods:
listen 127.0.0.1:8000; listen 127.0.0.1 不加端口,默认监听80端口; listen 8000 listen *:8000 listen localhost:8000
Parsing the uri and port in the listen directive
From the above content As you know, listen has many uses. We need to obtain the port number and uri part of the listen instruction when parsing. nginx provides the ngx_parse_url() method to parse the uri and port. This function will be called when parsing the listen instruction.
ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u) { u_char *p; size_t len; p = u->url.data; len = u->url.len; // 这里是解析unix domain的协议 if (len >= 5 && ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) { return ngx_parse_unix_domain_url(pool, u); } // 解析ipv6协议 if (len && p[0] == '[') { return ngx_parse_inet6_url(pool, u); } // 解析ipv4协议 return ngx_parse_inet_url(pool, u); }
We are using the ipv4 protocol. Here we analyze the ngx_parse_inet_url() function
// u.url = "80"; // u.listen = 1; // u.default_port = 80; static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) { u_char *p, *host, *port, *last, *uri, *args; size_t len; ngx_int_t n; struct sockaddr_in *sin; #if (ngx_have_inet6) struct sockaddr_in6 *sin6; #endif u->socklen = sizeof(struct sockaddr_in); sin = (struct sockaddr_in *) &u->sockaddr; sin->sin_family = af_inet;// ipv4类型 u->family = af_inet; host = u->url.data; // "80" last = host + u->url.len; // host的最后字符的位置 port = ngx_strlchr(host, last, ':'); // 找到port, 这里为 null uri = ngx_strlchr(host, last, '/'); // 找到uri,这里为 null args = ngx_strlchr(host, last, '?'); // 找到参数args,这里为 null if (args) { if (uri == null || args < uri) { uri = args; } } if (uri) { if (u->listen || !u->uri_part) { u->err = "invalid host"; return ngx_error; } u->uri.len = last - uri; u->uri.data = uri; last = uri; if (uri < port) { port = null; } } if (port) { port++; len = last - port; n = ngx_atoi(port, len); if (n < 1 || n > 65535) { u->err = "invalid port"; return ngx_error; } u->port = (in_port_t) n; sin->sin_port = htons((in_port_t) n); u->port_text.len = len; u->port_text.data = port; last = port - 1; } else { if (uri == null) { if (u->listen) { /* test value as port only */ n = ngx_atoi(host, last - host); if (n != ngx_error) { if (n < 1 || n > 65535) { u->err = "invalid port"; return ngx_error; } u->port = (in_port_t) n; sin->sin_port = htons((in_port_t) n); u->port_text.len = last - host; u->port_text.data = host; u->wildcard = 1; return ngx_ok; } } } u->no_port = 1; u->port = u->default_port; sin->sin_port = htons(u->default_port); } len = last - host; if (len == 0) { u->err = "no host"; return ngx_error; } u->host.len = len; u->host.data = host; if (u->listen && len == 1 && *host == '*') { sin->sin_addr.s_addr = inaddr_any; u->wildcard = 1; return ngx_ok; } sin->sin_addr.s_addr = ngx_inet_addr(host, len); if (sin->sin_addr.s_addr != inaddr_none) { if (sin->sin_addr.s_addr == inaddr_any) { u->wildcard = 1; } u->naddrs = 1; u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); if (u->addrs == null) { return ngx_error; } sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in)); if (sin == null) { return ngx_error; } ngx_memcpy(sin, &u->sockaddr, sizeof(struct sockaddr_in)); u->addrs[0].sockaddr = (struct sockaddr *) sin; u->addrs[0].socklen = sizeof(struct sockaddr_in); p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1); if (p == null) { return ngx_error; } u->addrs[0].name.len = ngx_sprintf(p, "%v:%d", &u->host, u->port) - p; u->addrs[0].name.data = p; return ngx_ok; } if (u->no_resolve) { return ngx_ok; } if (ngx_inet_resolve_host(pool, u) != ngx_ok) { return ngx_error; } u->family = u->addrs[0].sockaddr->sa_family; u->socklen = u->addrs[0].socklen; ngx_memcpy(&u->sockaddr, u->addrs[0].sockaddr, u->addrs[0].socklen); switch (u->family) { #if (ngx_have_inet6) case af_inet6: sin6 = (struct sockaddr_in6 *) &u->sockaddr; if (in6_is_addr_unspecified(&sin6->sin6_addr)) { u->wildcard = 1; } break; #endif default: /* af_inet */ sin = (struct sockaddr_in *) &u->sockaddr; if (sin->sin_addr.s_addr == inaddr_any) { u->wildcard = 1; } break; } return ngx_ok; }
This function parses the address and port number of our listen. In our configuration file, the port The port number is 80, and no listening address is configured, so u->wildcard = 1, indicating that this is a wildcard and the port number of all IP addresses of the server should be monitored.
Parsing the listen command
Let’s take a look at the listen configuration from the source code:
{ ngx_string("listen"), ngx_http_srv_conf|ngx_conf_1more, ngx_http_core_listen, ngx_http_srv_conf_offset, 0, null }
We can know from the configuration file that listen Can only appear in the server module and can take multiple parameters.
The corresponding processing function is ngx_http_core_listen. Let’s analyze this function below. We have deleted some codes for error judgment.
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; if (ngx_parse_url(cf->pool, &u) != ngx_ok) { return ngx_conf_error; } ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t)); ngx_memcpy(&lsopt.sockaddr.sockaddr, &u.sockaddr, u.socklen); lsopt.socklen = u.socklen; lsopt.backlog = ngx_listen_backlog; lsopt.rcvbuf = -1; lsopt.sndbuf = -1; #if (ngx_have_setfib) lsopt.setfib = -1; #endif #if (ngx_have_tcp_fastopen) lsopt.fastopen = -1; #endif lsopt.wildcard = u.wildcard; #if (ngx_have_inet6) lsopt.ipv6only = 1; #endif (void) ngx_sock_ntop(&lsopt.sockaddr.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; } // 这里面的其他代码都是处理listen的各种参数,对我们这里的分析没有用处 } if (ngx_http_add_listen(cf, cscf, &lsopt) == ngx_ok) { return ngx_conf_ok; } return ngx_conf_error; }
The overall process of this function is to parse listen Each parameter of the command generates an ngx_http_listen_opt_t. As the name suggests, this structure saves some listening port options (listening port option). A function ngx_parse_url() is called here. We have analyzed it above. The function of this function is to parse the address and port in the url.
Then the most important part is coming. The ngx_http_core_listen() function calls the ngx_http_add_listen() function at the end. This function saves the listen port information to the ports dynamic array of the ngx_http_core_main_conf_t structure. .
ngx_http_add_listen() function
// cf: 配置结构体 // cscf: listen指令所在的server的配置结构体 // lsopt : ngx_http_core_listen()生成的listen option 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; ngx_http_conf_port_t *port; ngx_http_core_main_conf_t *cmcf; // 获取 ngx_http_core_module模块的main_conf结构体ngx_http_core_main_conf_t cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); // ports字段是一个数组 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->sockaddr.sockaddr; p = ngx_inet_get_port(sa); port = cmcf->ports->elts; for (i = 0; i < cmcf->ports->nelts; i++) { if (p != port[i].port || sa->sa_family != port[i].family) { continue; } /* a port is already in the port list */ return ngx_http_add_addresses(cf, cscf, &port[i], lsopt); } /* add a port to the port list */ 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); }
This function saves the port number information into the port field of the ngx_http_core_main_conf_t structure.
The above is the detailed content of How to use the listen command in nginx. For more information, please follow other related articles on the PHP Chinese website!