真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

nginx關(guān)于域名解析的源碼分析

在nginx中,nginx需要頻繁進(jìn)行域名解析的過程做了自己的優(yōu)化,使用了自己的一套域名解析過程,并做了緩存處理。我們可以設(shè)置DNS解析服務(wù)器的地址,即通過resolver指令來設(shè)置DNS服務(wù)器的地址,由此來啟動nginx的域名解析。

創(chuàng)新互聯(lián)長期為千余家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為平塘企業(yè)提供專業(yè)的網(wǎng)站設(shè)計、做網(wǎng)站,平塘網(wǎng)站改版等技術(shù)服務(wù)。擁有10多年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。

本文,我們來看看nginx是如何做的,這里我們只選出重要的代碼進(jìn)行分析,完整代碼請參考nginx源代碼,本文基于nginx-1.0.6版本進(jìn)行的分析。

首先,來看看resolver的初始化。
在ngx_http_core_loc_conf_s的聲明中,可以看到對reolver:

struct ngx_http_core_loc_conf_s { ngx_resolver_t *resolver; /* resolver */ }

resolver中保存了與域名解析相關(guān)的一些數(shù)據(jù),它保存了DNS的本地緩存,通過紅黑樹的方式來組織數(shù)據(jù),以達(dá)到快速查找。

typedef struct { ngx_event_t *event; // 用于連接dns服務(wù)器 ngx_udp_connection_t *udp_connection; // 保存了本地緩存的DNS數(shù)據(jù) ngx_rbtree_t name_rbtree; ngx_rbtree_node_t name_sentinel; } ngx_resolver_t;

在nginx初始化的時候,通過ngx_resolver_create來初始化這一結(jié)構(gòu)體,如果有設(shè)置resolver,則在ngx_http_core_resolver中有調(diào)用:

static char * ngx_http_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_core_loc_conf_t *clcf = conf; // 初始化,第二個參數(shù)是我們設(shè)置的域名解析服務(wù)器的IP地址 clcf->resolver = ngx_resolver_create(cf, &u.addrs[0]); if (clcf->resolver == NULL) { return NGX_OK; } return NGX_CONF_OK; }

來看看ngx_resolver_create做了些什么:

ngx_resolver_t * ngx_resolver_create(ngx_conf_t *cf, ngx_addr_t *addr) { ngx_resolver_t *r; ngx_udp_connection_t *uc; r = ngx_calloc(sizeof(ngx_resolver_t), cf->log); if (r == NULL) { return NULL; } // 省略了其它數(shù)據(jù)的初始化過程 r->event = ngx_calloc(sizeof(ngx_event_t), cf->log); if (r->event == NULL) { return NULL; } // 設(shè)置事件的句柄 r->event->handler = ngx_resolver_resend_handler; r->event->data = r; // 設(shè)置dns服務(wù)器的地址 if (addr) { uc = ngx_calloc(sizeof(ngx_udp_connection_t), cf->log); if (uc == NULL) { return NULL; } r->udp_connection = uc; uc->sockaddr = addr->sockaddr; uc->socklen = addr->socklen; uc->server = addr->name; } return r; }

初始化好了之后,就可以調(diào)用了。在nginx中,upstream中使用到了此方法的域名解析。我們結(jié)合proxy模塊與upstream模塊來實例講解吧,注意在proxy中,只有當(dāng)proxy_pass中包含有變量時,才會用到nginx自己的DNS解析。而且這里有一個需要特別注意的,如果proxy_pass中包含變量,那么nginx中就需要配置resolver來指定DNS服務(wù)器地址了,否則,將直接返回502錯誤。從下面的代碼中我們可以看到。
首先,在ngx_http_proxy_handler函數(shù)中,有如下代碼:

static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r) { // 這里的意思是,如果沒有變量,就不進(jìn)行變量解析 if (plcf->proxy_lengths == NULL) { ctx->vars = plcf->vars; u->schema = plcf->vars.schema; } else { // 只有當(dāng)proxy_pass里面包含變量時,才解析變量,在ngx_http_proxy_eval中會添加域名解析的需求,請看ngx_http_proxy_eval的實現(xiàn) if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } }

而在proxy模塊的ngx_http_proxy_eval函數(shù)中,可以看到如下代碼:

static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf) { ngx_str_t proxy; ngx_url_t url; // proxy為要轉(zhuǎn)向的url url.url.data = proxy.data + add; url.default_port = port; url.uri_part = 1; // 注意這里設(shè)置的為不用解析域名 url.no_resolve = 1; // 由于有設(shè)置不用解析域名,所以在ngx_parse_url中就不會對域名進(jìn)行解析 if (ngx_parse_url(r->pool, &url) != NGX_OK) { return NGX_ERROR; } // 保存與需要解析域名相關(guān)的信息 u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); if (u->resolved == NULL) { return NGX_ERROR; } if (url.addrs && url.addrs[0].sockaddr) { // 如果域名已經(jīng)是ip地址的格式,就保存起來,這樣在upstream里面就不會再進(jìn)行解析 // 在upsteam模塊里面會判斷u->resolved->sockaddr是否為空 u->resolved->sockaddr = url.addrs[0].sockaddr; u->resolved->socklen = url.addrs[0].socklen; u->resolved->naddrs = 1; u->resolved->host = url.addrs[0].name; } else { u->resolved->host = url.host; u->resolved->port = (in_port_t) (url.no_port ? port : url.port); u->resolved->no_port = url.no_port; } }

所以,可以看出,只在當(dāng)proxy_pass到包含變量的url時,才有可能進(jìn)行域名的解析。因為如果是固定的url,則完全可以在初始化的時候解析域名,而不用在請求的時候進(jìn)行了。關(guān)于這部分代碼的實現(xiàn),可以參考ngx_http_upstream_init_round_robin函數(shù),而且注意,在proxy_pass時,是直接添加upstream來實現(xiàn)的,等有機(jī)會介紹upstream代碼時再做解釋。
接下來在upstream中ngx_http_upstream_init_request在初始化請求時,當(dāng)u->resolved為不空時,需要解析域名??创a:

static void ngx_http_upstream_init_request(ngx_http_request_t *r) { ngx_str_t *host; ngx_http_upstream_t *u; u = r->upstream; // 如果已經(jīng)是ip地址格式了,就不需要再進(jìn)行解析 if (u->resolved->sockaddr) { if (ngx_http_upstream_create_round_robin_peer(r, u->resolved) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } ngx_http_upstream_connect(r, u); return; } // 接下來就要開始查找域名 host = &u->resolved->host; temp.name = *host; // 初始化域名解析器 ctx = ngx_resolve_start(clcf->resolver, &temp); if (ctx == NULL) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } // 返回NGX_NO_RESOLVER表示無法進(jìn)行域名解析 if (ctx == NGX_NO_RESOLVER) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no resolver defined to resolve %V", host); ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY); return; } // 設(shè)置需要解析的域名的類型與信息 ctx->name = *host; ctx->type = NGX_RESOLVE_A; // 解析完成后的回調(diào)函數(shù) ctx->handler = ngx_http_upstream_resolve_handler; ctx->data = r; u->resolved->ctx = ctx; // 開始解析域名 if (ngx_resolve_name(ctx) != NGX_OK) { u->resolved->ctx = NULL; ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } // 域名還沒有解析完成,則直接返回 return; // 其它動作 }

在上面的代碼中,我們可以看到,需要解析域名,我們調(diào)用ngx_resolve_start,設(shè)置好回調(diào)函數(shù)等上下文信息后,然后再調(diào)用ngx_resolve_name,等域名解析完成后會調(diào)用ngx_http_upstream_resolve_handler。
那ngx_resolve_start函數(shù)的主要工作是初始化當(dāng)前解析請求的上下文:

ngx_resolver_ctx_t * ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp) { in_addr_t addr; ngx_resolver_ctx_t *ctx;

if (temp) { addr = ngx_inet_addr(temp->name.data, temp->name.len); // 如果要解析的地址已為為ip地址,則會設(shè)置temp->quick為1,那么在調(diào)用ngx_resolve_name時就不會進(jìn)行域名解析,在后面代碼中可以看到 if (addr != INADDR_NONE) { temp->resolver = r; temp->state = NGX_OK; temp->naddrs = 1; temp->addrs = &temp->addr; temp->addr = addr;


新聞標(biāo)題:nginx關(guān)于域名解析的源碼分析
轉(zhuǎn)載來于:http://weahome.cn/article/cgppgi.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部