分享

关于gethostbyname多线程阻塞的处理方法

 lycbje 2013-12-30
      

一、方法分析
 

Linux环境下gethostbyname函数是用来向DNS查询一个域名的IP地址。 由于DNS的查询方式是递归查询,在网络不通的情况下会导致gethostbyname函数在查询一个域名时出现严重超时问题。而该函数又不能像connectread等函数那样通过setsockopt或者select函数那样设置超时时间,因此常常成为程序开发的瓶颈。

在多线程环境下,gethostbyname会出现一个非常严重的问题,就是如果有一个线程的gethostbyname发生阻塞,其它线程都会在gethostbyname处发生阻塞,直到该线程的gethostbyname函数返回为止。针对这样的问题我们应该怎么处理呢?

下面介绍两种方法:

1、      使用alarm设定信号,如果超时就用sigsetjmpsiglongjmp跳过gethostbyname函数。

2、      独立开启一个线程来调用gethostbyname函数,该线程除了调用此函数外,不做任何事情。
 

二、方法介绍

1alarm设定信号方法

    (1)sigsetjmpsiglongjmp概述

        sigsetjmp:  参数为非0的时候,会保存进程的当前信号屏蔽字

        siglongjmp: 恢复保存的信号屏蔽字

    (2)、使用方法

  1. #include <setjmp.h>
  2. #include <time.h>
  3.  
  4. static sigjmp_buf jmpbuf;
  5. static void alarm_func()
  6. {
  7.      siglongjmp(jmpbuf, 1);
  8. }
  9.  
  10. static struct hostent *gngethostbyname(char *HostName, int timeout)
  11. {
  12.      struct hostent *lpHostEnt;
  13.  
  14.      signal(SIGALRM, alarm_func);
  15.      if(sigsetjmp(jmpbuf, 1) != 0)
  16.      {
  17.            alarm(0); /* 取消闹钟 */
  18.            signal(SIGALRM, SIG_IGN);
  19.            return NULL;
  20.      }
  21.      alarm(timeout); /* 设置超时时间 */
  22.      lpHostEnt = gethostbyname(HostName);
  23.      signal(SIGALRM, SIG_IGN);
  24.  
  25.      return lpHostEnt;
  26. }
2、多线程方法

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <netdb.h>
  4. #include <pthread.h>
  5.   
  6.   
  7.  char address[64] = {"0.0.0.0"};
  8.  
  9.  void *_GetHostName2Ip(void *HostName)
  10.  {
  11.       char *pstHostName = NULL;
  12.  
  13.       struct hostent *hptr;
  14.  
  15.       pstHostName = (char *)HostName;
  16.       hptr = gethostbyname(pstHostName);
  17.       if(NULL == hptr)
  18.       {
  19.           pthread_exit(-1);
  20.       }
  21.      
  22.       inet_ntop(hptr->h_addrtype, hptr->h_addr, address, 32);
  23.       pthread_exit(0);
  24. }

  25. int main()
  26. {
  27.      int kill_err = 0;
  28.      static char cHostName[256]; /* 域名地址,根据需要自己设定 */
  29.  
  30.      pthread_t gethostname;
  31.     
  32.      kill_err = pthread_kill(gethostname, 0);
  33.      if(ESRCH == kill_err) /* 判断线程是否存在 */
  34.      {
  35.          pthread_create(&gethostname, NULL, _GetHostName2Ip, (void *)cHostName);
  36.      }
  37.      else if(EINVAL == kill_err) /* 信号非法 */
  38.      {
  39.          return -1;
  40.      }
  41.  
  42.     printf("address = %s\n", address);

  43.     return 0;
  44.  }
通过实际应用与测试,在多线程环境下,多线程方法是最适用的,如果应用alarm信号可能会导致无法预知的问题。需要说明指出的是:多线程方法和alarm信号设定只是在嵌入式设备中进行测试过,如果使用到其它地方请详加仔细验证。由于知识有限,难免有疏漏和错误,请读者给予指正......
    


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多