解决无网络环境下getaddrinfo引发的超时问题

问题背景:

源码中在调用getaddrinfo时,如果是网络正常的环境下,getaddrinfo返回会很快,但如果无网络,机器就无法进行dns解析,从而导致getaddrinfo返回时间高达1-2分钟以上。

解决方案:使用多线程执行getaddrinfo

源码如下:

//add by xdl
struct stu_dns_info
{
    LPCSTR node;
    LPCSTR servname;
    struct addrinfo *hints;
    struct addrinfo **res;
    pthread_t pid;
};

void *thread_get_addr_info(void *arg)
{
    pthread_detach(pthread_self());
    int ret = 0;
    struct stu_dns_info *s_dns_info = (struct stu_dns_info *)arg;
    
    char *node = NULL;
    char* servname = NULL;

    if(s_dns_info->node != NULL)
    {
        node = strdup(s_dns_info->node);
    }
    if(s_dns_info->servname !=NULL)
    {
        servname = strdup(s_dns_info->servname);
    }
       
    struct addrinfo hints;
    hints.ai_socktype = s_dns_info->hints->ai_socktype;
    hints.ai_protocol = s_dns_info->hints->ai_protocol;
    hints.ai_flags = s_dns_info->hints->ai_flags;
    struct addrinfo* res = NULL;
    pthread_t pid_master = s_dns_info->pid;

    ret = getaddrinfo(node, servname, &hints, &res);   
    FIXME("xdl result = %d\n", ret);
    if(ret != 0)
    {        
        goto out;
    }
    
    ret = pthread_kill(pid_master, 0);
    if(0 == ret)
    {
        if(s_dns_info->res == NULL)
        {
            freeaddrinfo(res);
            goto out;
        }
        *(s_dns_info->res) = res;
    }
    else
    {
        freeaddrinfo(res);
    }

out:
    if (node != NULL)
        free(node);
    if (servname != NULL)
        free(servname);

    pthread_exit(NULL);
}
int WINAPI my_getaddrinfo(LPCSTR node, LPCSTR servname, struct addrinfo *punixhints, struct addrinfo **unixaires)
{
    pthread_t t1 = 0;
    int ret = 0;
    int count = 0;

    struct stu_dns_info s_dns_info;
    s_dns_info.node = node;
    s_dns_info.servname = servname;
    s_dns_info.hints = punixhints;
    s_dns_info.res = unixaires;
    s_dns_info.pid = pthread_self();

    ret = pthread_create(&t1, NULL, thread_get_addr_info, (void *)&s_dns_info);
    if(ret == -1)
    {
        FIXME("pthread_create error\n");
        return -1;
    }
    //int result = getaddrinfo(node, servname, punixhints, unixaires);    
    int btimeout = 1;
    for(count = 0; count < 20; ++count)
    {
        ret = pthread_kill(t1, 0);
        if(0 == ret)
        {
            FIXME("thread exist\n");
            usleep(100*1000);//100ms
        }
        else if(ESRCH == ret)
        {
            FIXME("thread not exist\n");
            btimeout = 0;
            break;
        }        
    }
    if( 0 == btimeout && NULL != *(s_dns_info.res))
    {
        ret = 0;
    }
    else
    {
        ret = -1;
    }        
    return ret;
}
//end

主线程中每100ms循环一次,通过pthread_kill检测子线程是否还存在,超时时间2s,同样,子线程也会去检测主线程是否还在,子线程中结构体数据使用strdup进行了保存,防止主线程退出后,传进来的指针数据丢失。

参考:浅谈getaddrinfo函数的超时处理机制_haima1998的专栏-CSDN博客_getaddrinfo阻塞

おすすめ

転載: blog.csdn.net/xiadeliang1111/article/details/120481521