前言:
而今同学们对“nginx端口监听配置文件”可能比较讲究,小伙伴们都想要知道一些“nginx端口监听配置文件”的相关知识。那么小编同时在网摘上网罗了一些关于“nginx端口监听配置文件””的相关知识,希望兄弟们能喜欢,姐妹们一起来学习一下吧!1. 概述 懂的人都看总结详细教程资料+课件 关注+后台私信;资料;两个字可以免费视频领取+文档+各大厂面试题 资料内容包括:C/C++,Linux,golang,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,嵌入式 等。
监听端口属于 server 虚拟主机,它是由 server{} 块下的 listen 配置项决定的。
每监听一个 TCP 端口,都将使用一个独立的 ngx_rtmp_conf_port_t 结构体来表示:
typedef struct { /* socket 地址家族 */ int family; /* 监听端口 */ in_port_t port; /* 监听的端口下对应着的所有 ngx_rtmp_conf_addr_t 地址 */ ngx_array_t addrs; /* array of ngx_rtmp_conf_addr_t */} ngx_rtmp_conf_port_t;
一个端口,可能对应着多个地址(当主机上有多个 IP 地址时),该地址用 ngx_rtmp_conf_addr_t 表示:
typedef struct { struct sockaddr *sockaddr; socklen_t socklen; ngx_rtmp_conf_ctx_t *ctx; unsigned bind:1; unsigned wildcard:1;#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) unsigned ipv6only:2;#endif unsigned so_keepalive:2; unsigned proxy_protocol:1;#if (NGX_HAVE_KEEPALIVE_TUNABLE) int tcp_keepidle; int tcp_keepintvl; int tcp_keepcnt;#endif} ngx_rtmp_conf_addr_t;
在 ngx_rtmp_core_main_conf_t 结构体中,保存着 nginx.conf 中所有需要监听的端口:
typedef struct { ... /* 该数组保存着的元素是指向 ngx_rtmp_listen_t 结构体的指针, * 每个元素代表一个需要监听的端口 */ ngx_array_t listen; /* ngx_rtmp_listen_t */ ...}ngx_rtmp_core_main_conf_t;
Nginx 每从 nginx.conf 中解析中一个 listen 配置项,就把该配置项的值组织成 ngx_rtmp_listen_t 结构体添加到
ngx_rtmp_core_main_conf_t 的成员 listen 数组中,如下:
typedef struct { u_char sockaddr[NGX_SOCKADDRLEN]; socklen_t socklen; /* server ctx */ ngx_rtmp_conf_ctx_t *ctx; unsigned bind:1; unsigned wildcard:1;#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) unsigned ipv6only:2;#endif unsigned so_keepalive:2; unsigned proxy_protocol:1;#if (NGX_HAVE_KEEPALIVE_TUNABLE) int tcp_keepidle; int tcp_keepintvl; int tcp_keepcnt;#endif} ngx_rtmp_listen_t;
对同一个端口 1935,可以同时监听 127.0.0.1:8000、192.168.56.101:1935 这两个地址,当一台物理机器具备多个 IP
地址时这是很有用的。对应到 RTMP 的框架上,Nginx 是使用 ngx_rtmp_conf_addr_t 结构体来表示一个对应着具体地址
的监听端口,因此,一个 ngx_rtmp_conf_port_t 将会对应多个 ngx_rtmp_conf_addr_t,而 ngx_rtmp_conf_addr_t 是
以动态数组的形式保存在 ngx_rtmp_conf_port_t 中的 addrs 成员中的。
2. 监听端口的解析与管理2.1 ngx_rtmp_core_listen:解析 listen 配置项
static char *ngx_rtmp_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){ size_t len, off; in_port_t port; ngx_str_t *value; ngx_url_t u; ngx_uint_t i, m; ngx_module_t **modules; struct sockaddr *sa; ngx_rtmp_listen_t *ls; struct sockaddr_in *sin; ngx_rtmp_core_main_conf_t *cmcf;#if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6;#endif /* 指向 "listen xxx" 配置项,如 "listen 1935" */ value = cf->args->elts; ngx_memzero(&u, sizeof(ngx_url_t)); /* 将监听的端口赋给 u.url,如 "1935" */ u.url = value[1]; u.listen = 1; /* 解析该监听的端口 */ 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; } cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); ls = cmcf->listen.elts; /* 遍历listen数组,若有元素,将待监听的地址与数组中的保存的地址进行比较, * 若有相同的,则返回错误,否则添加到listen数组中 */ for (i = 0; i < cmcf->listen.nelts; i++) { sa = (struct sockaddr *) ls[i].sockaddr; if (sa->sa_family != u.family) { continue; } switch (sa->sa_family) {#if (NGX_HAVE_INET6) case AF_INET6: off = offsetof(struct sockaddr_in6, sin6_addr); len = 16; sin6 = (struct sockaddr_in6 *) sa; port = sin6->sin6_port; break;#endif default: /* AF_INET */ off = offsetof(struct sockaddr_in, sin_addr); len = 4; sin = (struct sockaddr_in *) sa; port = sin->sin_port; break; } if (ngx_memcmp(ls[i].sockaddr + off, (u_char *) &u.sockaddr + off, len) != 0) { continue; } if (port != u.port) { continue; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "duplicate \"%V\" address and port pair", &u.url); return NGX_CONF_ERROR; } ls = ngx_array_push(&cmcf->listen); if (ls == NULL) { return NGX_CONF_ERROR; } ngx_memzero(ls, sizeof(ngx_rtmp_listen_t)); ngx_memcpy(ls->sockaddr, (u_char *) &u.sockaddr, u.socklen); ls->socklen = u.socklen; ls->wildcard = u.wildcard; ls->ctx = cf->ctx;#if (nginx_version >= 1009011) modules = cf->cycle->modules;#else modules = ngx_modules;#endif for (m = 0; modules[m]; m++) { if (modules[m]->type != NGX_RTMP_MODULE) { continue; } } /* 若监听端口后面还附加有其他条件,则进行处理,否则直接返回 */ for (i = 2; i < cf->args->nelts; i++) { if (ngx_strcmp(value[i].data, "bind") == 0) { ls->bind = 1; continue; } if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) struct sockaddr *sa; u_char buf[NGX_SOCKADDR_STRLEN]; sa = (struct sockaddr *) ls->sockaddr; if (sa->sa_family == AF_INET6) { if (ngx_strcmp(&value[i].data[10], "n") == 0) { ls->ipv6only = 1; } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) { ls->ipv6only = 0; } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid ipv6only flags \"%s\"", &value[i].data[9]); return NGX_CONF_ERROR; } ls->bind = 1; } else { len = ngx_sock_ntop(sa,#if (nginx_version >= 1005003) ls->socklen,#endif buf, NGX_SOCKADDR_STRLEN, 1); ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "ipv6only is not supported " "on addr \"%*s\", ignored", len, buf); } continue;#else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "bind ipv6only is not supported " "on this platform"); return NGX_CONF_ERROR;#endif } if (ngx_strncmp(value[i].data, "so_keepalive=", 13) == 0) { if (ngx_strcmp(&value[i].data[13], "on") == 0) { ls->so_keepalive = 1; } else if (ngx_strcmp(&value[i].data[13], "off") == 0) { ls->so_keepalive = 2; } else {#if (NGX_HAVE_KEEPALIVE_TUNABLE) u_char *p, *end; ngx_str_t s; end = value[i].data + value[i].len; s.data = value[i].data + 13; p = ngx_strlchr(s.data, end, ':'); if (p == NULL) { p = end; } if (p > s.data) { s.len = p - s.data; ls->tcp_keepidle = ngx_parse_time(&s, 1); if (ls->tcp_keepidle == (time_t) NGX_ERROR) { goto invalid_so_keepalive; } } s.data = (p < end) ? (p + 1) : end; p = ngx_strlchr(s.data, end, ':'); if (p == NULL) { p = end; } if (p > s.data) { s.len = p - s.data; ls->tcp_keepintvl = ngx_parse_time(&s, 1); if (ls->tcp_keepintvl == (time_t) NGX_ERROR) { goto invalid_so_keepalive; } } s.data = (p < end) ? (p + 1) : end; if (s.data < end) { s.len = end - s.data; ls->tcp_keepcnt = ngx_atoi(s.data, s.len); if (ls->tcp_keepcnt == NGX_ERROR) { goto invalid_so_keepalive; } } if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0 && ls->tcp_keepcnt == 0) { goto invalid_so_keepalive; } ls->so_keepalive = 1;#else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the \"so_keepalive\" parameter accepts " "only \"on\" or \"off\" on this platform"); return NGX_CONF_ERROR;#endif } ls->bind = 1; continue;#if (NGX_HAVE_KEEPALIVE_TUNABLE) invalid_so_keepalive: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid so_keepalive value: \"%s\"", &value[i].data[13]); return NGX_CONF_ERROR;#endif } if (ngx_strcmp(value[i].data, "proxy_protocol") == 0) { ls->proxy_protocol = 1; continue; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the invalid \"%V\" parameter", &value[i]); return NGX_CONF_ERROR; } return NGX_CONF_OK;}2.2 ngx_rtmp_add_ports: 将监听端口添加到 ports 数组中
static ngx_int_t ngx_rtmp_add_ports(ngx_conf_t *cf, ngx_array_t *ports, ngx_rtmp_listen_t *listen){ in_port_t p; ngx_uint_t i; struct sockaddr *sa; struct sockaddr_in *sin; ngx_rtmp_conf_port_t *port; ngx_rtmp_conf_addr_t *addr;#if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6;#endif sa = (struct sockaddr *) &listen->sockaddr; switch (sa->sa_family) {#if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) sa; p = sin6->sin6_port; break;#endif default: /* AF_INET */ sin = (struct sockaddr_in *) sa; p = sin->sin_port; break; } /* 首先比较 ports 数组中是否已经存在该待监听端口的,若已经存在, * 则不用再次添加了,直接跳到 found 下,否则添加一个新的端口 */ port = ports->elts; for (i = 0; i < ports->nelts; i++) { if (p == port[i].port && sa->sa_family == port[i].family) { /* a port is already in the port list */ port = &port[i]; goto found; } } /* add a port to the port list */ port = ngx_array_push(ports); if (port == NULL) { return NGX_ERROR; } port->family = sa->sa_family; port->port = p; if (ngx_array_init(&port->addrs, cf->temp_pool, 2, sizeof(ngx_rtmp_conf_addr_t)) != NGX_OK) { return NGX_ERROR; }found: /* 这里有可能一个端口对应几个 IP 地址 */ addr = ngx_array_push(&port->addrs); if (addr == NULL) { return NGX_ERROR; } addr->sockaddr = (struct sockaddr *) &listen->sockaddr; addr->socklen = listen->socklen; addr->ctx = listen->ctx; addr->bind = listen->bind; addr->wildcard = listen->wildcard; addr->so_keepalive = listen->so_keepalive; addr->proxy_protocol = listen->proxy_protocol;#if (NGX_HAVE_KEEPALIVE_TUNABLE) addr->tcp_keepidle = listen->tcp_keepidle; addr->tcp_keepintvl = listen->tcp_keepintvl; addr->tcp_keepcnt = listen->tcp_keepcnt;#endif#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) addr->ipv6only = listen->ipv6only;#endif return NGX_OK;}2.3 ngx_rtmp_optimize_servers
static char *ngx_rtmp_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports){ ngx_uint_t i, p, last, bind_wildcard; ngx_listening_t *ls; ngx_rtmp_port_t *mport; ngx_rtmp_conf_port_t *port; ngx_rtmp_conf_addr_t *addr; port = ports->elts; for (p = 0; p < ports->nelts; p++) { ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts, sizeof(ngx_rtmp_conf_addr_t), ngx_rtmp_cmp_conf_addrs); addr = port[p].addrs.elts; last = port[p].addrs.nelts; /* * if there is the binding to the "*:port" then we need to bind() * to the "*:port" only and ignore the other bindings */ if (addr[last - 1].wildcard) { addr[last - 1].bind = 1; bind_wildcard = 1; } else { bind_wildcard = 0; } i = 0; while (i < last) { if (bind_wildcard && !addr[i].bind) { i++; continue; } /* 创建并初始化 ngx_listening_t 结构体 */ ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen); if (ls == NULL) { return NGX_CONF_ERROR; } ls->addr_ntop = 1; ls->handler = ngx_rtmp_init_connection; ls->pool_size = 4096; /* TODO: error_log directive */ ls->logp = &cf->cycle->new_log; ls->log.data = &ls->addr_text; ls->log.handler = ngx_accept_log_error; ls->keepalive = addr[i].so_keepalive;#if (NGX_HAVE_KEEPALIVE_TUNABLE) ls->keepidle = addr[i].tcp_keepidle; ls->keepintvl = addr[i].tcp_keepintvl; ls->keepcnt = addr[i].tcp_keepcnt;#endif#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) ls->ipv6only = addr[i].ipv6only;#endif mport = ngx_palloc(cf->pool, sizeof(ngx_rtmp_port_t)); if (mport == NULL) { return NGX_CONF_ERROR; } ls->servers = mport; if (i == last - 1) { mport->naddrs = last; } else { mport->naddrs = 1; i = 0; } switch (ls->sockaddr->sa_family) {#if (NGX_HAVE_INET6) case AF_INET6: if (ngx_rtmp_add_addrs6(cf, mport, addr) != NGX_OK) { return NGX_CONF_ERROR; } break;#endif default: /* AF_INET */ if (ngx_rtmp_add_addrs(cf, mport, addr) != NGX_OK) { return NGX_CONF_ERROR; } break; } addr++; last--; } } return NGX_CONF_OK;总结: 求关注一起免费学习
更多视频教程文档资料免费领取后台私信【资料】自行获取。
标签: #nginx端口监听配置文件