查询完成后回调在ngx_resolver_ctx_t中指定的方法 真正的DNS查询完成后 , 不管成功 , 失败或是超时 , nginx会回调相应查询的handler, 如前面设置的:ngx_mail_smtp_resolve_name_handler 。在handler中都需要调用ngx_resolve_addr_done来标识查询结束 。static voidngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx){ in_addr_t addr; ngx_uint_t i; ngx_connection_t *c; struct sockaddr_in *sin; ngx_mail_session_t *s;s = ctx->data; c = s->connection;if (ctx->state) { ngx_log_error(NGX_LOG_ERR, c->log, 0, ""%V" could not be resolved (%i: %s)", &ctx->name, ctx->state, ngx_resolver_strerror(ctx->state)); } else { /* AF_INET only */ sin = (struct sockaddr_in *) c->sockaddr;for (i = 0; i < ctx->naddrs; i++) { addr = ctx->addrs[i];ngx_log_debug4(NGX_LOG_DEBUG_MAIL, c->log, 0, "name was resolved to %ud.%ud.%ud.%ud", (ntohl(addr) >> 24) & 0xff, (ntohl(addr) >> 16) & 0xff, (ntohl(addr) >> 8) & 0xff, ntohl(addr) & 0xff);if (addr == sin->sin_addr.s_addr) { goto found; } }s->host = smtp_unavailable; } found: //不管成功失败都要执行 ngx_resolve_name_done(ctx);}二、域名解析流程分析
文章插图
通过Nginx进行域名查询的流程图如下 , 颜色越深花费的时间越长 。调用过程分为三种:
- 首先判断是不是IPv4地址 , 如果是就直接调用Handler
- 再次检查是不是在缓存中 , 如果有 , 就调用Handler
- 最后发送远程DNS请求 , 收到回复后调用Handler
三、查询场景分析及实现介绍
查询的地址是IP v4地址
比如74.125.128.100, nginx会在ngx_resolve_start中通过ngx_inet_addr方法进行判断 , 如果是IPv4的地址 , 就设置好标志位 ngx_resolver_ctx_t->quick , 在接下来的ngx_resolve_name中会对这个标志位进行判断 , 如果为1 , 就直接调用ngx_resolver_ctx_t->handler
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);if (addr != INADDR_NONE) { temp->resolver = r; temp->state = NGX_OK; temp->naddrs = 1; temp->addrs = &temp->addr; temp->addr = addr; temp->quick = 1;return temp; } } ...}
- 超时没有得到查询结果
- 调用ngx_resolve_name时设置的回调方法被调用 , 同时ngx_resolver_ctx_t->state被设置为NGX_RESOLVE_TIMEDOUT 。相应的代码为:
static voidngx_resolver_timeout_handler(ngx_event_t *ev){ ngx_resolver_ctx_t *ctx; ctx = ev->data; ctx->state = NGX_RESOLVE_TIMEDOUT; ctx->handler(ctx);}
- 正常查询一个不在缓存中的域名
- 如果要查询的域名不在缓存中 , 首先把域名按hash值放在缓存中 , 然后准备查询需要的数据 , 发送DNS查询的UDP请求给DNS服务器 ,
static ngx_int_tngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx){ ngx_resolver_node_t *rn; rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t)); ngx_rbtree_insert(&r->name_rbtree, &rn->node); ngx_resolver_create_name_query(rn, ctx); ngx_resolver_send_query(r, rn);rn->cnlen = 0; rn->naddrs = 0; rn->valid = 0; rn->waiting = ctx;ctx->state = NGX_AGAIN;} //收到DNS查询结果后的回调方法static voidngx_resolver_read_response(ngx_event_t *rev){ ssize_t n; ngx_connection_t *c; u_char buf[NGX_RESOLVER_UDP_SIZE]; c = rev->data;do { n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE); if (n < 0) { return; }ngx_resolver_process_response(c->data, buf, n); } while (rev->ready);} static voidngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans){ hash = ngx_crc32_short(name.data, name.len); rn = ngx_resolver_lookup_name(r, &name, hash);//copy addresses to cached node rn->u.addrs = addrs;//回调所有等待本域名解析的请求 next = rn->waiting; rn->waiting = NULL;while (next) { ctx = next; ctx->state = NGX_OK; ctx->naddrs = naddrs; ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs; ctx->addr = addr; next = ctx->next;ctx->handler(ctx); }}
- 对同一域名查询多次查询
- 如果多次查询时 , 之前的查询结果还在缓存中并且没有失效 , 就直接从缓存中取到查询结果 , 并调用设置的回调方法 。
static ngx_int_tngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx){ uint32_t hash; in_addr_t addr, *addrs; ngx_uint_t naddrs; ngx_resolver_ctx_t *next; ngx_resolver_node_t *rn;hash = ngx_crc32_short(ctx->name.data, ctx->name.len); rn = ngx_resolver_lookup_name(r, &ctx->name, hash);if (rn) { if (rn->valid >= ngx_time()) { naddrs = rn->naddrs;if (naddrs) { ctx->next = rn->waiting; rn->waiting = NULL;do { ctx->state = NGX_OK; ctx->naddrs = naddrs; ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs; ctx->addr = addr; next = ctx->next;ctx->handler(ctx);ctx = next; } while (ctx);return NGX_OK; } } }}
推荐阅读
-
决战!平安京|决战平安京,返校季大揭秘,新手最全攻略!!!
-
十大蓝牙小音箱排行榜,酷狗蘑蘑小音节奏闪灯一键DJ“城会玩”
-
风筝|《追风筝的人》: 每个人终其一生,都在追逐属于自己的命运
-
电视剧|同样是扮演“乞丐”,孙俪流鼻涕,周星驰抢狗盆,而他本色出演!
-
赵露思|《骄阳似我》又传出新阵容,李现将搭档赵露思,你认为符合吗?
-
顶级奢侈品集团Kering的代表品牌及产地和代表作品或风格有哪些
-
易简财经|27万股民今夜无眠,黄了!两家券商千亿级合并告吹
-
华为|华为迎来大消息!俄外长刚刚表态,俄罗斯准备与中国以及华为开展5G技术合作
-
-
-
亚美尼亚人|二十世纪初,亚美尼亚人遭到了大屠杀,100万人死于土耳其人之手
-
『雷帝网』CFO称汽车业回报周期长 亏损是阶段性的,恒大健康亏近50亿
-
拜登|美国下任总统已定?拜登犯下“致命”错误,这次奥巴马也“保不住”他!
-
-
-
时尚旅游守在富豪门前32年,谁能让他动就奖励一万,印度最“尽职”保安
-
口腔科张兴医生:种植牙要如何护理?牙科医生教你4招,轻松延长使用寿命!很实用
-
权志龙否认吸毒传闻,曾被指在机场行为异常,疑似毒瘾发作,12年前曾承认吸毒
-
-