这是我参加比赛得到的题目

 

  1. 开发一个域名批量查询程序,文本文件data.txt中存储着N个域名,每行一个,  
  2. 要求程序从该文件中读取域名数据,然后获取该域名对应的IP地址列表.比如  
  3. 文件内容为:  
  4. www.126.com  
  5. www.132321321.com  
  6. www.baidu.com  
  7. 输出格式为:  
  8. 域名  
  9. IP个数  
  10. IP1  
  11. IP2  
  12. ...  
  13. 例如,上面的例子文件中的输出结果为:  
  14. www.126.com  
  15. 1  
  16. 121.20.3.105  
  17. www.132321321.com  
  18. 0  
  19. www.baidu.com  
  20. 3  
  21. 212.32.4.211  
  22. 10.52.32.32  
  23. 102.31.0.91 
为了加快查询速度我采取了多线程(最大线程数通过参数控制)的方法,下面是我设计的程序流程(以3个线程为例):

 

多线程解析域名_多线程 

下面是我设计保存结果的,由于我用的是多线程,因此用链表保存,这样不会出现线程之间同时修改同一个变量的问题,这样不需要加上锁,只需要把链表指针传入,我设计的链表是一个链表上的各个节点又各自保存另一个链表(保存每个域名的多个ip)

多线程解析域名_职场_02 

 

源代码:

 

  1. /*  
  2.  * 系统环境:Linux kernel 2.6.18 gcc 4.1.2 pthread,dns服务器使用/etc/resolv.conf的配置  
  3.  * 编译: gcc test1.c -o test1 -lpthread  
  4.     输入参数:  
  5.                参数1:数据文件路径,必须  
  6.                参数2:线程数,不输入则默认为4,最小值为1  
  7.  * 运行: ./test1 datafilename <max thread num> 默认线程数为4  
  8.  * 例子: ./test1 d.txt  
  9.  * 例子: ./test1 d.txt 3   
  10.  * ----------------------------------------------------------------------------------------------------  
  11.  * Copyright (c) 2010 by yifangyou   
  12.  * All rights reserved  
  13.  * ----------------------------------------------------------------------------------------------------  
  14.  * 开发一个域名批量查询程序,文本文件data.txt中存储着N个域名,每行一个,  
  15.  * 要求程序从该文件中读取域名数据,然后获取该域名对应的IP地址列表.比如  
  16.  * 文件内容为:  
  17.  * www.126.com  
  18.  * www.132321321.com  
  19.  * www.baidu.com  
  20.  * 输出格式为:  
  21.  * 域名  
  22.  * IP个数  
  23.  * IP1  
  24.  * IP2  
  25.  * ...  
  26.  * 例如,上面的例子文件中的输出结果为:  
  27.  *   
  28.  * www.126.com  
  29.  * 1  
  30.  * 121.20.3.105  
  31.  * www.132321321.com  
  32.  * 0  
  33.  * www.baidu.com  
  34.  * 3  
  35.  * 212.32.4.211  
  36.  * 10.52.32.32  
  37.  * 102.31.0.91  
  38.  *----------------------------------------------------------------------------------------------------  
  39.  * 本程序的数据结构是  
  40.  * query_list_head  
  41.  * ->query_list1---------------------------->query_list2-------------------->query_list3  
  42.  *                      ->domain1 ->domain  
  43.  *                      ip_num1 ip_num  
  44.  *                      host_list_head host_list_head  
  45.  *                      ->ip1->ip2->ip3 ->ip2_1->ip2_2->ip2_3  
  46.  */  
  47.    
  48. #include <stdio.h> /* for printf */   
  49. #include <stdlib.h> /* for malloc */  
  50. #include <string.h> /* for strlen,strdup */  
  51. #include <errno.h> /* for inet_ntoa */  
  52. #include <sys/socket.h> /* for inet_ntoa */  
  53. #include <netinet/in.h> /* for inet_ntoa */  
  54. #include <arpa/inet.h> /* for inet_ntoa */  
  55. #include <netdb.h> /* for gethostbyname */  
  56. #include <pthread.h> /* for pthread_create,pthread_join*/  
  57. #include <stddef.h> /* for offsetof*/  
  58. #define MAX_INPUT_LEN        512 /* for max line size */  
  59. #define MAX_THREAD            4 /* for thread pool maxsize */  
  60.  
  61. //list head  
  62. struct llhead {  
  63.     struct llhead *prev, *next;  
  64. };  
  65. //list init  
  66. #define LL_INIT(N) ((N)->next = (N)->prev = (N))  
  67.  
  68. //get the n node  
  69. #define LL_ENTRY(P,T,N) ((T *) ((char *) (P) - offsetof(T,N)))  
  70.  
  71. //append into list,into a queue list   
  72. #define LL_APPEND(H, N) \  
  73.   do { \  
  74.     ((H)->prev)->next = (N); \  
  75.     (N)->prev = ((H)->prev); \  
  76.     (N)->next = (H); \  
  77.     (H)->prev = (N); \  
  78.   } while (0)  
  79.  
  80. //loop over all elements in a queue  
  81. #define LL_FOREACH_SAFE(H,N,T) \  
  82.   for (N = (H)->next, T = (N)->next; N != (H); \  
  83.       N = (T), T = (N)->next)  
  84. /****************************************************************  
  85.  * iplist *  
  86.  ****************************************************************/  
  87. struct host {  
  88.     char *ip;  
  89.     struct llhead host_list;  
  90. };  
  91. /****************************************************************  
  92.  * result *  
  93.  ****************************************************************/  
  94. struct query_result{  
  95.     char *domain;  
  96.     int ip_num;  
  97.     struct llhead host_list_head;  
  98.     struct llhead query_list;  
  99. };  
  100.  
  101. /****************************************************************  
  102.  * result *  
  103.  ****************************************************************/  
  104. struct query_list{  
  105.     struct llhead query_list_head;  
  106. };  
  107. /****************************************************************  
  108.  * add a ip to result's ip list *  
  109.  ****************************************************************/  
  110. struct query_result * addquery(struct query_list * qlist,const char *domain)  
  111. {  
  112.     struct query_result *qr=NULL;  
  113.     if ((qr = malloc(sizeof(*qr))) != NULL)   
  114.     {  
  115.         qr->domain = strdup(domain);  
  116.         qr->ip_num=0;  
  117.         LL_APPEND(&qlist->query_list_head, &qr->query_list);  
  118.         LL_INIT(&qr->host_list_head);  
  119.         return qr;  
  120.     }else 
  121.     {  
  122.         perror(strerror(errno));   
  123.         return NULL;  
  124.     }  
  125. }  
  126.  
  127. /****************************************************************  
  128.  * add a ip to result's ip list *  
  129.  ****************************************************************/  
  130. int addhost(struct query_result * qr,const char *ip)  
  131. {  
  132.   struct host *hp=NULL;  
  133.   if ((hp = malloc(sizeof(*hp))) != NULL)   
  134.   {  
  135.       hp->ip = strdup(ip);  
  136.       LL_APPEND(&qr->host_list_head, &hp->host_list);  
  137.       return 0;  
  138.   }else 
  139.   {  
  140.       perror(strerror(errno));   
  141.       return -1;  
  142.   }  
  143. }  
  144. /****************************************************************  
  145.  * print the result and free ip list *  
  146.  ****************************************************************/  
  147. void printAndFree(struct query_result * qr){  
  148.     struct llhead *lp=NULL, *tmp=NULL;  
  149.     struct host *hp=NULL;  
  150.     printf("%s\n",qr->domain);  
  151.     printf("%d\n",qr->ip_num);  
  152.     LL_FOREACH_SAFE(&qr->host_list_head, lp, tmp)   
  153.     {  
  154.         hp = LL_ENTRY(lp, struct host, host_list);  
  155.         printf("%s\n",hp->ip);  
  156.         free(hp->ip);  
  157.         free(hp);  
  158.     }  
  159. }  
  160.  
  161. /****************************************************************  
  162.  * print all result and free all query result *  
  163.  ****************************************************************/  
  164. void printResult(struct query_list * qlist){  
  165.      struct llhead *lp=NULL, *tmp=NULL;  
  166.     struct query_result *qr=NULL;  
  167.     LL_FOREACH_SAFE(&qlist->query_list_head,lp, tmp)   
  168.     {  
  169.         qr = LL_ENTRY(lp, struct query_result, query_list);  
  170.         printAndFree(qr);  
  171.         free(qr->domain);  
  172.         free(qr);  
  173.     }  
  174. }  
  175.  
  176. /****************************************************************  
  177.  * resolve the domain get addrlist and record the ip *  
  178.  ****************************************************************/  
  179. int get_ip_list(struct query_result * qr)  
  180. {   
  181.     if(qr==NULL)  
  182.         {  
  183.         return -1;      
  184.         }  
  185.     int i=0;   
  186.     char *p=NULL;  
  187.     char *domain=qr->domain;  
  188.     struct hostent *h=gethostbyname(domain);   
  189.     if(h==NULL)  
  190.     {  
  191.         perror(strerror(errno));  
  192.         return -1;   
  193.     }  
  194.     while(p=h->h_addr_list[i++])  
  195.     {  
  196. //     printf("domain=%s,ip=%s\n",domain,inet_ntoa(*(struct in_addr*)p));  
  197.         addhost(qr,inet_ntoa(*(struct in_addr*)p));  
  198.         qr->ip_num++;  
  199.     }  
  200.     return 0;   
  201. }   
  202. /****************************************************************  
  203.  * read a line from file *  
  204.  ****************************************************************/  
  205. int next_input_line(FILE *fp,char *line, int n) {  
  206.     char *result=NULL;  
  207.     do   
  208.     {  
  209.         result = fgets(line, n, fp);  
  210.     } while ((result != NULL) &&(line[0] == '\n'));  
  211.  
  212.     if (result == NULL)  
  213.     {  
  214.         return (0);      
  215.     }  
  216.     else 
  217.         {  
  218.         return (strlen(line));  
  219.     }  
  220. }  
  221. /****************************************************************  
  222.  * remove blank char before str *  
  223.  ****************************************************************/  
  224. char *ltrim(char*p_str)  
  225. {  
  226.     char *p_tmp=p_str;  
  227.     while(isspace(*p_tmp)!=0)  
  228.     {  
  229.         p_tmp++;  
  230.     }  
  231.     return p_tmp;  
  232. }  
  233. /****************************************************************  
  234.  * remove blank char after str *  
  235.  ****************************************************************/  
  236. void rtrim(char*p_str)  
  237. {  
  238.     char *p_tmp=p_str+strlen(p_str)-1;  
  239.     while(isspace(*p_tmp)!=0)  
  240.     {  
  241.         *p_tmp='\0';  
  242.         p_tmp--;  
  243.     }  
  244. }  
  245. /****************************************************************  
  246.  * remove blank char after and before str *  
  247.  ****************************************************************/  
  248. char *trim(char*p_str)  
  249. {  
  250.     rtrim(p_str);  
  251.     return ltrim(p_str);  
  252. }  
  253.  
  254. /****************************************************************  
  255.  * is a number string *  
  256.  ****************************************************************/  
  257. int is_numeric(char*p_str)  
  258. {  
  259.     while(*p_str)  
  260.     {  
  261.         if(!isdigit(*p_str))  
  262.         {  
  263.             return 0;      
  264.         }  
  265.         p_str++;  
  266.     }  
  267.     return 1;  
  268. }  
  269.  
  270. /****************************************************************  
  271.  * main *  
  272.  ****************************************************************/  
  273. int main(int argc,char **argv)   
  274. {   
  275.     if(argc < 2)  
  276.     {  
  277.         perror("need a filename\n");  
  278.     }  
  279.     //get max thread number  
  280.     int max_thread=MAX_THREAD;  
  281.     if(argc>=3)  
  282.     {  
  283.         if(is_numeric(argv[2]))  
  284.         {  
  285.             max_thread=atoi(argv[2]);  
  286.             if(max_thread<=0)  
  287.             {  
  288.                 max_thread=MAX_THREAD;  
  289.             }  
  290.         }  
  291.     }  
  292.     if(max_thread<=0)  
  293.         max_thread=MAX_THREAD;  
  294.     //open data file  
  295.     FILE *fp=NULL;  
  296.     if ((fp = fopen(argv[1], "r")) == NULL) {  
  297.         perror("Error: unable to open datafile\n");  
  298.         return -1;  
  299.     }  
  300.     //init query list  
  301.     struct query_list *qlist=NULL;  
  302.     if((qlist=(struct query_list *)malloc(sizeof(struct query_list)))==NULL)  
  303.     {  
  304.         perror(strerror(errno));  
  305.         if (fclose(fp) != 0)   
  306.         {  
  307.             perror("Error: unable to close datafile\n");  
  308.             return (-1);  
  309.         }  
  310.         return -1;  
  311.     }  
  312.     LL_INIT(&qlist->query_list_head);  
  313.     int j=0;  
  314.     //read file finish flag  
  315.     int got_eof = 0;  
  316.     int thread_i=0;  
  317.     //thread pool  
  318.     pthread_t *pids=(pthread_t *)malloc(max_thread*sizeof(pthread_t));  
  319.     memset(pids,0,max_thread*sizeof(pthread_t));  
  320.     while(got_eof==0)  
  321.     {  
  322.         int input_length = MAX_INPUT_LEN;  
  323.         char input_line[MAX_INPUT_LEN + 1]={0};  
  324.         int len = next_input_line(fp,input_line, input_length);  
  325.         if (len == 0)   
  326.         {  
  327.             //read file finish  
  328.             got_eof = 1;  
  329.                 }else   
  330.                 {  
  331.             char * domain=trim(input_line);  
  332.             if(strlen(domain)==0)  
  333.             {  
  334.                  //skip empty line  
  335.                 continue;  
  336.             }  
  337.             struct query_result *qr=addquery(qlist,domain);  
  338.             //multi_thread to resolv the domain  
  339.             if((pthread_create(&pids[thread_i],NULL,(void *) get_ip_list,(void *)qr))!=0)  
  340.             {  
  341.                 printf ("Create pthread error!\n");  
  342.                 exit (1);  
  343.             }  
  344.             thread_i++;  
  345.             if(thread_i >= max_thread)  
  346.             {  
  347.                 for(j=0;j<max_thread;j++)  
  348.                 {  
  349.                     //waiting for all thread finish  
  350.                     if(pids[j]!=0)  
  351.                     {  
  352.                         pthread_join(pids[j], NULL);  
  353.                         pids[j]=0;  
  354.                     }          
  355.                 }  
  356.                 //next loop  
  357.                 thread_i=0;  
  358.             }  
  359.         }      
  360.     }  
  361.     //if exists unfinish thread wait   
  362.     for(j=0;j<max_thread;j++)  
  363.     {  
  364.         if(pids[j]!=0)  
  365.         {  
  366.             pthread_join(pids[j], NULL);      
  367.             pids[j]=0;          
  368.         }  
  369.     }  
  370.     free(pids);  
  371.     //output the result  
  372.     printResult(qlist);  
  373.     free(qlist);  
  374.       //close file  
  375.     if (fclose(fp) != 0)   
  376.     {  
  377.         perror("Error: unable to close datafile\n");  
  378.         return (-1);  
  379.     }  
  380.     return 0;