Linux调用 gethostbyname 接口返回失败

1. 问题现象

在连接上网络的情况下,使用 linux 命令 nslookup 查看域名,可以正常解析到对应的IP地址,但在代码中调用 gethostbyname 函数返回失败。

2. 问题原因

2.1 打印错误信息

当 gethostbyname 发生错误时,它不设置 errno 变量,而是将全局变量 h_errno 设置为<netdb.h>中定义的常值之一。

h_errno 是在 C 语言中用于存储 DNS 查询错误代码的全局变量。当使用 gethostbyname 或 gethostbyaddr 等函数进行域名解析时,如果发生错误,h_errno 会被设置为一个错误代码,这个代码可以用来确定错误的类型,以下是一些常见的 h_errno 错误代码及其含义:

  • (1)HOST_NOT_FOUND:没有找到主机(域名无法解析)。
  • (2)TRY_AGAIN:再次尝试(通常是临时性错误,如网络问题)。
  • (3)NO_RECOVERY:不可恢复的错误(如格式错误)。
  • (4)NO_DATA(等同于NO_ADDRESS):没有数据记录(域名解析没有返回任何数据)。

注:前面的编号表示错误码号。

 h_errno需要使用 herror 打印,可通过 hstrerror 查看错误码对应的详细信息:

herror("gethostbyname failed");

printf("gethostbyname failed, id is %d, %s.\n", h_errno, hstrerror(h_errno));

博主这里调用 h_errno 打印的错误信息为:Host name lookup failure

报该错误的原因可能是代码中有其它地方更新了DNS解析缓存,导致应用程序的网络不通

注:可通过仅重启该应用程序来确定是否为该原因;如果应用程序重启后 gethostbyname 解析成功了,即可定位为该问题。

2.2 根因分析

gethostbyname 这个DNS解析器系统调用,其查询的信息来自于系统DNS解析缓存( 库函数只读一次存储dns的文件,放到缓存里);当之前存在过错误的解析或者说解析错误时,系统DNS解析缓存不会被更新,因此之后再调用就会一直失败。

因此当DNS SERVER信息更新后,gethostbyname就会解析不出地址了。

3. 解决措施

更新解析缓存。当出现 gethostbyname 调用失败时,使用 res_init() 函数来更新DNS缓存,然后再调用 gethostbyname。

注: res_init 函数用来初始化 DNS 解析库,成功返回0,失败返回-1。

4. 例程

#include <stdio.h>
#include <netdb.h>
#include <resolv.h>


int test(const char* hostname)
{
    struct hostent* host = gethostbyname(hostname);

    if (NULL == host) {
        herror("gethostbyname failed");
        //printf("gethostbyname failed, id is %d, %s.\n", h_errno, hstrerror(h_errno));
        if (TRY_AGAIN == h_errno) {
            if (res_init() != 0) {
                printf("res_init error\n");
                return -2;
            } else {
                printf("Init DNS configuration again\n");
                return 1;
            }
        } else {
            return -1;
        }
    }

    return 0;
}

void main(void)
{
    int ret;
    const char* hostName = "www.baidu.com";

    ret = test(hostName);
    if (ret > 0) {
        ret = test(hostName); //重读一次.
        if (0 == ret) {
            printf("gethostbyname Pass after one retry.\n");
        } else {
            printf("gethostbyname still fail after one retry.\n");
        }
    } else if (0 == ret) {
        printf("gethostbyname One-time pass.\n");
    } else {
        printf("gethostbyname unknow error\n");
    }

    return;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值