server中的server_name形成hash,優化server_name查找
核心函數ngx_http_optimize_servers(ngx_conf_t*cf, ngx_http_core_main_conf_t* cmcf)
因爲listen端口數據結構是[port,addr]二維數組,所以二層遍歷,每一個port,每一個addr是該函數的主流程。
遍歷addr是相同port下的addr,調用函數ngx_http_server_names
ngx_http_server_names(cf,cmcf, &addr[a])
函數首先ngx_hash_keys_array_init(&ha,NGX_HASH_LARGE)
這個函數是創建
typedef struct {
ngx_uint_t hsize;
ngx_pool_t *pool;
ngx_pool_t *temp_pool;
ngx_array_t keys;//保存hash信息,value是該server_name的server上下文
ngx_array_t *keys_hash; //保存server_name
ngx_array_t dns_wc_head;//hash信息
ngx_array_t *dns_wc_head_hash;//保存server_name
ngx_array_t dns_wc_tail; //hash信息
ngx_array_t *dns_wc_tail_hash;//保存server_name
} ngx_hash_keys_arrays_t;
ngx_http_server_names函數首先構建server_name數組(數組類型爲ngx_hash_key_t),包括絕對server_name和正則server_name,其中server正則可以是如下幾種:
1.example.com
2*.example.com
構建server_name的hash信息,根據server_name類別分別保存到keys(絕對匹配)、dns_wc_head(1和2這兩種類型) 、和dns_wc_tail(第三種類型),函數後面根據生成的這三個數組分表把這些信息保存
keys <=====> addr->hash
dns_wc_head <=====> addr->wc_head
dns_wc_tail <=====> addr->wc_tail
回到函數ngx_http_optimize_servers
每一個端口都會盜用ngx_http_init_listening
函數ngx_http_init_listening遍歷port下面的每一個addr,
調用ngx_http_add_listening(cf,&addr[i])首先創建和追加一個ngx_listening_t到cf->cycle->listening中去,也就是說cf->cycle->listening保存着該地址信息
ls->addr_ntop-1
ls->handler= ngx_http_init_connection//這裏設置listening的回調函數
整個函數就是把addr裏面的值保存到ngx_listening_t下面去。
ls->server= hport
static ngx_int_t
ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport,
ngx_http_conf_addr_t *addr)
{
ngx_uint_t i;
ngx_http_in_addr_t *addrs;
struct sockaddr_in *sin;
ngx_http_virtual_names_t *vn;
hport->addrs = ngx_pcalloc(cf->pool,
hport->naddrs * sizeof(ngx_http_in_addr_t));
if (hport->addrs == NULL) {
return NGX_ERROR;
}
addrs = hport->addrs;
for (i = 0; i < hport->naddrs; i++) {
sin = &addr[i].opt.u.sockaddr_in;
addrs[i].addr = sin->sin_addr.s_addr;//保存地址
addrs[i].conf.default_server = addr[i].default_server;
#if (NGX_HTTP_SSL)
addrs[i].conf.ssl = addr[i].opt.ssl;
#endif
if (addr[i].hash.buckets == NULL
&& (addr[i].wc_head == NULL
|| addr[i].wc_head->hash.buckets == NULL)
&& (addr[i].wc_tail == NULL
|| addr[i].wc_tail->hash.buckets == NULL)
#if (NGX_PCRE)
&& addr[i].nregex == 0
#endif
)
{
continue;
}
vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t));
if (vn == NULL) {
return NGX_ERROR;
}
addrs[i].conf.virtual_names = vn;//指向虛擬name
vn->names.hash = addr[i].hash;//addr的exact地址
vn->names.wc_head = addr[i].wc_head;//正則head地址
vn->names.wc_tail = addr[i].wc_tail;//正則tail地址
#if (NGX_PCRE)
vn->nregex = addr[i].nregex;
vn->regex = addr[i].regex;
#endif
}
return NGX_OK;
整個cycle->listening結構如下
ngx_init_cycle->ngx_open_listening_sockets
函數主要是遍歷cycle->listenning的每一個需要監聽的sock,調用socket api來完成sock初始化
1 socket
2 bind
3 listen
4 accept
然後就開始分析main主流程了