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主流程了