10.3 监听端口的管理

监听端口属于server虚拟主机,它是由server{}块下的listen配置项决定的。同时,它与server{}块对应的ngx_http_core_srv_conf_t结构体密切相关,本节将介绍这两者间的关系,以及监听端口的数据结构。

每监听一个TCP端口,都将使用一个独立的ngx_http_conf_port_t结构体来表示,如下所示。


typedef struct{

//socket地址家族

ngx_int_t family;

//监听端口

in_port_t port;

//监听的端口下对应着的所有ngx_http_conf_addr_t地址

ngx_array_t addrs;

}ngx_http_conf_port_t;


这个保存着监听端口的ngx_http_conf_port_t将由全局的ngx_http_core_main_conf_t结构体保存。下面再来看一下ports容器,如下所示。


typedef struct{

//存放着该http{}配置块下监听的所有ngx_http_conf_port_t端口

ngx_array_t*ports;

……

}ngx_http_core_main_conf_t;


在前面的代码中,ngx_http_conf_port_t的addrs动态数组可能不太容易理解。可先回顾一下listen配置项的语法,在10.1节的例子中,对同一个端口8000,我们可以同时监听127.0.0.1:8000、173.39.160.51:8000这两个地址,当一台物理机器具备多个IP地址时这是很有用的。具体到HTTP框架的实现上,Nginx是使用ngx_http_conf_addr_t结构体来表示一个对应着具体地址的监听端口的,因此,一个ngx_http_conf_port_t将会对应多个ngx_http_conf_addr_t,而ngx_http_conf_addr_t就是以动态数组的形式保存在addrs成员中的。

下面再来看看ngx_http_conf_addr_t的定义,如下所示。


typedef struct{

//监听套接字的各种属性

ngx_http_listen_opt_t opt;

/以下3个散列表用于加速寻找到对应监听端口上的新连接,确定到底使用哪个server{}虚拟主机下的配置来处理它。所以,散列表的值就是ngx_http_core_srv_conf_t结构体的地址/

//完全匹配server name的散列表

ngx_hash_t hash;

//通配符前置的散列表

ngx_hash_wildcard_t*wc_head;

//通配符后置的散列表

ngx_hash_wildcard_t*wc_tail;

if(NGX_PCRE)

//下面的regex数组中元素的个数

ngx_uint_t nregex;

/*regex指向静态数组,其数组成员就是ngx_http_server_name_t结构体,表示正则表达式及其匹配

的server{}虚拟主机*/

ngx_http_server_name_t*regex;

endif

//该监听端口下对应的默认server{}虚拟主机

ngx_http_core_srv_conf_t*default_server;

//servers动态数组中的成员将指向ngx_http_core_srv_conf_t结构体

ngx_array_t servers;

}ngx_http_conf_addr_t;


在上面的servers动态数组中,保存的数据类型是ngx_http_core_srv_conf_t**,简单来说,就是由servers数组把监听的端口与server{}虚拟主机关联起来了。图10-9展示了10.1节的例子中监听端口与server{}虚拟主机间在内存中的关系。

10.3 监听端口的管理 - 图1

图 10-9 监听端口与server{}虚拟主机间的关系

下面来解释一下图10-9。整个http{}块下共监听了3个端口,分别是80、8000、8080,因此,ngx_http_core_main_conf_t中的ports动态数组有3个ngx_http_conf_port_t成员存放这3个端口。除了8000端口对应了两个ngx_http_conf_addr_t结构体外(分别是127.0.0.1:8000和173.39.160.51:8000),80和8080都相当于默认监听了该端口下的所有地址(实际上,listen 80就相当于listen.80),因此,这两个端口各自对应了一个ngx_http_conf_addr_t结构体。每个监听地址ngx_http_conf_addr_t的servers动态数组中关联着监听地址对应的server{}虚拟主机,根据10.1节的例子可以知道,server A配置块对应着监听地址.80和127.0.0.1:8000,而server B配置块对应着监听地址.80、.8080和173.39.160.51:8000。

对于每一个监听地址ngx_http_conf_addr_t,都会有8.3.1节中介绍过的ngx_listening_t与其相对应,而ngx_listening_t的handler回调方法设置为ngx_http_init_connection,所以,新的TCP连接成功建立后都会调用ngx_http_init_connection方法初始化HTTP相关的信息,第11章将会详细介绍ngx_http_init_connection方法的实现。