ngx_http_add_listen
声明在 src\http\ngx_http.h
ngx_int_t ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_http_listen_opt_t *lsopt);
定义在 src\http\ngx_http.c
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;
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->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);
}
这个函数是Nginx在解析配置时用于添加监听端口的核心逻辑
函数签名
返回值:
ngx_int_t
NGX_OK
(0):成功添加监听配置。NGX_ERROR
(-1):内存分配失败或地址冲突等错误
参数
ngx_conf_t *cf
- 类型 :指向
ngx_conf_t
结构体的指针。- 作用 :
表示 Nginx 配置解析的上下文(Context),包含当前解析的配置文件路径、内存池(temp_pool
)、日志对象等关键信息
ngx_http_core_srv_conf_t *cscf
- 类型 :指向
ngx_http_core_srv_conf_t
结构体的指针。- 作用 :
表示当前正在配置的 HTTPserver
块的核心配置。每个server
块在 Nginx 中对应一个虚拟主机,该结构体存储了与该虚拟主机相关的配置信息。
ngx_http_listen_opt_t *lsopt
- 类型 :指向
ngx_http_listen_opt_t
结构体的指针。- 作用 :
封装了从配置文件中解析出的listen
指令参数。例如,用户配置listen 80;
或listen 443 ssl;
时,参数会被解析到该结构体中。
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
获取 HTTP 核心模块的主配置结构体
定义在
src\http\ngx_http_config.h
#define ngx_http_conf_get_module_main_conf(cf, module) \ ((ngx_http_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index]
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;
}
}
cmcf->ports
是ngx_http_core_main_conf_t
结构体中的一个动态数组(ngx_array_t
),用于存储所有监听端口的配置如果
ports
为NULL
,表示这是首次添加监听端口,需要初始化数组
cf->temp_pool
:内存池(ngx_pool_t
),用于分配数组内存。配置阶段的临时内存池(temp_pool
)会在配置解析完成后被释放或重置。2
:数组的初始容量(预分配 2 个元素的空间),减少后续扩容的次数。sizeof(ngx_http_conf_port_t)
:数组元素的大小,每个元素对应一个监听端口的配置。ngx_http_core_main_conf_t-CSDN博客
sa = lsopt->sockaddr;
获取监听配置中的套接字地址结构
p = ngx_inet_get_port(sa);
从套接字地址结构中提取端口号 ,并将其转换为主机字节序(Host Byte Order),以便后续逻辑处理
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);
}
遍历已存在的端口列表
若端口号或协议族不匹配,跳过当前端口,继续检查下一个
匹配成功
ngx_http_add_addresses
:将当前监听地址(lsopt
)添加到已存在的端口配置(port[i]
)的地址列表中
- 合并同一端口的多个监听配置,避免重复绑定(例如多个
server
块监听80
端口的不同 IP 地址)。- 减少
bind()
系统调用次数,提升性能。此时 ports->nelts=0
/* 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;
添加一个新元素到数组中
ngx_http_conf_port_t-CSDN博客
return ngx_http_add_address(cf, cscf, port, lsopt);
将新的监听地址(
lsopt
)添加到指定端口(port
)的地址列表中ngx_http_add_address-CSDN博客