[nginx源碼分析]server_name hash

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

3 www.example.*

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





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章