根據域名解析出該域名所綁定的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(const char* url, int second);
int main()
{
resolv_name("www.test2test.com", 1);
return 0;
}
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjump;
static void
sig_alrm(int signo)
{
if (!canjump)
return;
siglongjmp(jmpbuf, 1); /* jump back to main, don't return */
canjump = 0;
}
int resolv_name(const char* 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));
}
}
return 0;
}
不過這個策略還是有問題的,這個API通過alarm函數設定了一個定時器,超時的時候發送一個SIGALARM信號,如果系統中已經存在了通過alarm定制的定時器,如果解決這些定時器可能發生的沖突問題?如果有更好的辦法,歡迎提示.