当我们的程序是单进程的时候,居如connect、read、accept、gethostbyname之类的网络API函数默认都是阻塞的,想实现connect、read、accept的非阻塞版本很容易,之需要将其调用的文件描述符(套接字)设置为非阻塞模式,然后交给select去捕捉返回结果即可。然而gethostbyname函数只需要传递一个域名作为参数,显然无法依靠设置文件描述符(套接字)的超时时间来让其在规定的时间内返回,如果指定域名存在DNS中存在且主机能够连上互联网还好,要是域名在DNS中不存在或者主机没有连上互联网,那样gethostbyname就会一直阻塞着整个进程直至到达系统超时时间,导致程序中的其他功能无法执行,显然代价是惨重的。那么有没有办法实现超时返回的gethostbyname函数呢?答案是肯定的。
这里我们使用的办法是设置一个时钟,如果gethostbyname在指定的时间内尚未返回,时钟会强制其返回,得到的返回值显然是空指针,等价于告诉用户主机未连如互联网或者该域名无法解析。为了实现这一功能,我们需要重新封装一个形如gethostbyname的函数来获取IP,并增加一个用来指定超时时间的参数。
#include <netdb.h> #include <setjmp.h> static sigjmp_buf jmpbuf; static void alarm_func() { siglongjmp(jmpbuf, 1); } static struct hostent *timeGethostbyname(const char *domain, int timeout) { struct hostent *ipHostent = NULL; signal(SIGALRM, alarm_func); if(sigsetjmp(jmpbuf, 1) != 0) { alarm(0);//timout signal(SIGALRM, SIG_IGN); return NULL; } alarm(timeout);//setting alarm ipHostent = gethostbyname(domain); signal(SIGALRM, SIG_IGN); return ipHostent; } int getIPbyDomain(const char* domain, char* ip) { struct hostent *answer; answer = timeGethostbyname(domain, 10); if (NULL == answer) { herror("gethostbyname");//the error function of itself return -1; } if (answer->h_addr_list[0]) inet_ntop(AF_INET, (answer->h_addr_list)[0], ip, 16); else return -1; return 0; }
这样,如果我们想获得域名”www.cpplive.com” 所指向的IP地址,且要求在3秒内返回结果,则可以调用如下语句实现:
char cppliveIP[32]; char cpplive[32] = {"www.cpplive.com"}; if (getIPbyDomain(cpplive, cppliveIP)) printf("The domain not exist or the network disconnected!\n"); else printf("The IP of %s is %s\n", cpplive, cppliveIP);
除非注明,文章均为CppLive 编程在线原创,转载请注明出处,谢谢。
jmpbuf线程安全吗
经过测试是线程不安全的。
alarm + 全局 buffer的问题,有一个adns和axe库都是可替代的库
嗯,如果用多线程的而且需要频繁解析域名的话,adns可是试一试。