1. 程式人生 > >帶超時機制的DNS解析API

帶超時機制的DNS解析API

根據域名解析出該域名所繫結的IP地址,這個是客戶端常做的工作,只有在解析成功之後,才能正確的與伺服器端建立連線.

一般常使用getaddrinfo,gethostbyname 之類的API來完成這個工作,但是,這些API都有一個問題,就是都不支援超時機制,假如客戶端呼叫這些API阻塞,給程式會帶來影響.

現在想要達到的目標就是:呼叫API去解析域名,如果在一個時間內不能解析成功,就報錯退出.

我查了一下資料,有一些庫可以支援這樣的要求,但是都需要自己去做DNS解析的工作,也就是需要自己去封包/解包DNS協議報文.顯然,這樣的事情工作量太大了,不在我考慮的範圍之中.

其實系統中有不少這樣的API,沒有阻塞機制,又不能設定超時引數,有沒有一個好的策略,可以既使用這些API,又能給它們加上超時機制.

我看了下APUE中關於sigsetjmp + alarm + siglongjmp的方式來處理這樣的問題,自己寫了一個簡單的demo,看來是可以滿足的:
#include 
<setjmp.h>
#include 
<stdio.h>
#include 
<sys/types.h>
#include 
<sys/socket.h>
#include 
<netdb.h>
#include 
<signal.h>
#include 
<string.h>int resolv_name(constchar* url, int second);

int main()
{
    resolv_name(
"www.test2test.com"1);
    
return0;
}

static sigjmp_buf                   jmpbuf;
staticvolatile sig_atomic_t        canjump;

staticvoid
sig_alrm(
int signo)
{
    
if (!canjump)
        
return;

    siglongjmp(jmpbuf, 
1);  /* jump back to main, don't return */
    canjump 
=0;
}

int resolv_name(constchar* url, int second)
{
    
struct addrinfo *result = NULL;
    
int ret;
    
struct addrinfo addr;

    memset(
&addr, 0 , sizeof(addr));
    addr.ai_socktype 
= SOCK_STREAM;

    
if (signal(SIGALRM, sig_alrm) == SIG_ERR)
        printf(
"signal(SIGALRM) error\n");
    canjump 
=1;
    
if (sigsetjmp(jmpbuf, 1)) 
    {
        printf(
"ending main\n");
        
return-1;
    }

    alarm(second);

    ret 
= getaddrinfo(url, NULL, &addr, &result);
    canjump 
=0;

    
if (!ret)
    {
        
struct addrinfo *pCurr = result;
        printf(
"the \'%s\' ip is:\n", url);
        
for (; pCurr; pCurr = pCurr->ai_next)
        {
            printf(
"%s\n", inet_ntoa(((struct sockaddr_in*)(pCurr->ai_addr))->sin_addr));
        }
    }

    
return0;
}


不過這個策略還是有問題的,這個API通過alarm函式設定了一個定時器,超時的時候傳送一個SIGALARM訊號,如果系統中已經存在了通過alarm定製的定時器,如果解決這些定時器可能發生的衝突問題?如果有更好的辦法,歡迎提示.