根據(jù)域名解析出該域名所綁定的IP地址,這個(gè)是客戶(hù)端常做的工作,只有在解析成功之后,才能正確的與服務(wù)器端建立連接.
一般常使用getaddrinfo,gethostbyname
之類(lèi)的API來(lái)完成這個(gè)工作,但是,這些API都有一個(gè)問(wèn)題,就是都不支持超時(shí)機(jī)制,假如客戶(hù)端調(diào)用這些API阻塞,給程序會(huì)帶來(lái)影響.
現(xiàn)在想要達(dá)到的目標(biāo)就是:調(diào)用API去解析域名,如果在一個(gè)時(shí)間內(nèi)不能解析成功,就報(bào)錯(cuò)退出.
我查了一下資料,有一些庫(kù)可以支持這樣的要求,但是都需要自己去做DNS解析的工作,也就是需要自己去封包/解包DNS協(xié)議報(bào)文.顯然,這樣的事情工作量太大了,不在我考慮的范圍之中.
其實(shí)系統(tǒng)中有不少這樣的API,沒(méi)有阻塞機(jī)制,又不能設(shè)置超時(shí)參數(shù),有沒(méi)有一個(gè)好的策略,可以既使用這些API,又能給它們加上超時(shí)機(jī)制.
我看了下APUE中關(guān)于sigsetjmp
+ alarm + siglongjmp的方式來(lái)處理這樣的問(wèn)題,自己寫(xiě)了一個(gè)簡(jiǎn)單的demo,看來(lái)是可以滿(mǎn)足的:
#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;
}
不過(guò)這個(gè)策略還是有問(wèn)題的,這個(gè)API通過(guò)alarm函數(shù)設(shè)定了一個(gè)定時(shí)器,超時(shí)的時(shí)候發(fā)送一個(gè)SIGALARM信號(hào),如果系統(tǒng)中已經(jīng)存在了通過(guò)alarm定制的定時(shí)器,如果解決這些定時(shí)器可能發(fā)生的沖突問(wèn)題?如果有更好的辦法,歡迎提示.