这是我参加比赛得到的题目
为了加快查询速度我采取了多线程(最大线程数通过参数控制)的方法,下面是我设计的程序流程(以3个线程为例):
- 开发一个域名批量查询程序,文本文件data.txt中存储着N个域名,每行一个,
- 要求程序从该文件中读取域名数据,然后获取该域名对应的IP地址列表.比如
- 文件内容为:
- www.126.com
- www.132321321.com
- www.baidu.com
- 输出格式为:
- 域名
- IP个数
- IP1
- IP2
- ...
- 例如,上面的例子文件中的输出结果为:
- www.126.com
- 1
- 121.20.3.105
- www.132321321.com
- 0
- www.baidu.com
- 3
- 212.32.4.211
- 10.52.32.32
- 102.31.0.91
下面是我设计保存结果的,由于我用的是多线程,因此用链表保存,这样不会出现线程之间同时修改同一个变量的问题,这样不需要加上锁,只需要把链表指针传入,我设计的链表是一个链表上的各个节点又各自保存另一个链表(保存每个域名的多个ip)
源代码:
- /*
- * 系统环境:Linux kernel 2.6.18 gcc 4.1.2 pthread,dns服务器使用/etc/resolv.conf的配置
- * 编译: gcc test1.c -o test1 -lpthread
- 输入参数:
- 参数1:数据文件路径,必须
- 参数2:线程数,不输入则默认为4,最小值为1
- * 运行: ./test1 datafilename <max thread num> 默认线程数为4
- * 例子: ./test1 d.txt
- * 例子: ./test1 d.txt 3
- * ----------------------------------------------------------------------------------------------------
- * Copyright (c) 2010 by yifangyou
- * All rights reserved
- * ----------------------------------------------------------------------------------------------------
- * 开发一个域名批量查询程序,文本文件data.txt中存储着N个域名,每行一个,
- * 要求程序从该文件中读取域名数据,然后获取该域名对应的IP地址列表.比如
- * 文件内容为:
- * www.126.com
- * www.132321321.com
- * www.baidu.com
- * 输出格式为:
- * 域名
- * IP个数
- * IP1
- * IP2
- * ...
- * 例如,上面的例子文件中的输出结果为:
- *
- * www.126.com
- * 1
- * 121.20.3.105
- * www.132321321.com
- * 0
- * www.baidu.com
- * 3
- * 212.32.4.211
- * 10.52.32.32
- * 102.31.0.91
- *----------------------------------------------------------------------------------------------------
- * 本程序的数据结构是
- * query_list_head
- * ->query_list1---------------------------->query_list2-------------------->query_list3
- * ->domain1 ->domain
- * ip_num1 ip_num
- * host_list_head host_list_head
- * ->ip1->ip2->ip3 ->ip2_1->ip2_2->ip2_3
- */
- #include <stdio.h> /* for printf */
- #include <stdlib.h> /* for malloc */
- #include <string.h> /* for strlen,strdup */
- #include <errno.h> /* for inet_ntoa */
- #include <sys/socket.h> /* for inet_ntoa */
- #include <netinet/in.h> /* for inet_ntoa */
- #include <arpa/inet.h> /* for inet_ntoa */
- #include <netdb.h> /* for gethostbyname */
- #include <pthread.h> /* for pthread_create,pthread_join*/
- #include <stddef.h> /* for offsetof*/
- #define MAX_INPUT_LEN 512 /* for max line size */
- #define MAX_THREAD 4 /* for thread pool maxsize */
- //list head
- struct llhead {
- struct llhead *prev, *next;
- };
- //list init
- #define LL_INIT(N) ((N)->next = (N)->prev = (N))
- //get the n node
- #define LL_ENTRY(P,T,N) ((T *) ((char *) (P) - offsetof(T,N)))
- //append into list,into a queue list
- #define LL_APPEND(H, N) \
- do { \
- ((H)->prev)->next = (N); \
- (N)->prev = ((H)->prev); \
- (N)->next = (H); \
- (H)->prev = (N); \
- } while (0)
- //loop over all elements in a queue
- #define LL_FOREACH_SAFE(H,N,T) \
- for (N = (H)->next, T = (N)->next; N != (H); \
- N = (T), T = (N)->next)
- /****************************************************************
- * iplist *
- ****************************************************************/
- struct host {
- char *ip;
- struct llhead host_list;
- };
- /****************************************************************
- * result *
- ****************************************************************/
- struct query_result{
- char *domain;
- int ip_num;
- struct llhead host_list_head;
- struct llhead query_list;
- };
- /****************************************************************
- * result *
- ****************************************************************/
- struct query_list{
- struct llhead query_list_head;
- };
- /****************************************************************
- * add a ip to result's ip list *
- ****************************************************************/
- struct query_result * addquery(struct query_list * qlist,const char *domain)
- {
- struct query_result *qr=NULL;
- if ((qr = malloc(sizeof(*qr))) != NULL)
- {
- qr->domain = strdup(domain);
- qr->ip_num=0;
- LL_APPEND(&qlist->query_list_head, &qr->query_list);
- LL_INIT(&qr->host_list_head);
- return qr;
- }else
- {
- perror(strerror(errno));
- return NULL;
- }
- }
- /****************************************************************
- * add a ip to result's ip list *
- ****************************************************************/
- int addhost(struct query_result * qr,const char *ip)
- {
- struct host *hp=NULL;
- if ((hp = malloc(sizeof(*hp))) != NULL)
- {
- hp->ip = strdup(ip);
- LL_APPEND(&qr->host_list_head, &hp->host_list);
- return 0;
- }else
- {
- perror(strerror(errno));
- return -1;
- }
- }
- /****************************************************************
- * print the result and free ip list *
- ****************************************************************/
- void printAndFree(struct query_result * qr){
- struct llhead *lp=NULL, *tmp=NULL;
- struct host *hp=NULL;
- printf("%s\n",qr->domain);
- printf("%d\n",qr->ip_num);
- LL_FOREACH_SAFE(&qr->host_list_head, lp, tmp)
- {
- hp = LL_ENTRY(lp, struct host, host_list);
- printf("%s\n",hp->ip);
- free(hp->ip);
- free(hp);
- }
- }
- /****************************************************************
- * print all result and free all query result *
- ****************************************************************/
- void printResult(struct query_list * qlist){
- struct llhead *lp=NULL, *tmp=NULL;
- struct query_result *qr=NULL;
- LL_FOREACH_SAFE(&qlist->query_list_head,lp, tmp)
- {
- qr = LL_ENTRY(lp, struct query_result, query_list);
- printAndFree(qr);
- free(qr->domain);
- free(qr);
- }
- }
- /****************************************************************
- * resolve the domain get addrlist and record the ip *
- ****************************************************************/
- int get_ip_list(struct query_result * qr)
- {
- if(qr==NULL)
- {
- return -1;
- }
- int i=0;
- char *p=NULL;
- char *domain=qr->domain;
- struct hostent *h=gethostbyname(domain);
- if(h==NULL)
- {
- perror(strerror(errno));
- return -1;
- }
- while(p=h->h_addr_list[i++])
- {
- // printf("domain=%s,ip=%s\n",domain,inet_ntoa(*(struct in_addr*)p));
- addhost(qr,inet_ntoa(*(struct in_addr*)p));
- qr->ip_num++;
- }
- return 0;
- }
- /****************************************************************
- * read a line from file *
- ****************************************************************/
- int next_input_line(FILE *fp,char *line, int n) {
- char *result=NULL;
- do
- {
- result = fgets(line, n, fp);
- } while ((result != NULL) &&(line[0] == '\n'));
- if (result == NULL)
- {
- return (0);
- }
- else
- {
- return (strlen(line));
- }
- }
- /****************************************************************
- * remove blank char before str *
- ****************************************************************/
- char *ltrim(char*p_str)
- {
- char *p_tmp=p_str;
- while(isspace(*p_tmp)!=0)
- {
- p_tmp++;
- }
- return p_tmp;
- }
- /****************************************************************
- * remove blank char after str *
- ****************************************************************/
- void rtrim(char*p_str)
- {
- char *p_tmp=p_str+strlen(p_str)-1;
- while(isspace(*p_tmp)!=0)
- {
- *p_tmp='\0';
- p_tmp--;
- }
- }
- /****************************************************************
- * remove blank char after and before str *
- ****************************************************************/
- char *trim(char*p_str)
- {
- rtrim(p_str);
- return ltrim(p_str);
- }
- /****************************************************************
- * is a number string *
- ****************************************************************/
- int is_numeric(char*p_str)
- {
- while(*p_str)
- {
- if(!isdigit(*p_str))
- {
- return 0;
- }
- p_str++;
- }
- return 1;
- }
- /****************************************************************
- * main *
- ****************************************************************/
- int main(int argc,char **argv)
- {
- if(argc < 2)
- {
- perror("need a filename\n");
- }
- //get max thread number
- int max_thread=MAX_THREAD;
- if(argc>=3)
- {
- if(is_numeric(argv[2]))
- {
- max_thread=atoi(argv[2]);
- if(max_thread<=0)
- {
- max_thread=MAX_THREAD;
- }
- }
- }
- if(max_thread<=0)
- max_thread=MAX_THREAD;
- //open data file
- FILE *fp=NULL;
- if ((fp = fopen(argv[1], "r")) == NULL) {
- perror("Error: unable to open datafile\n");
- return -1;
- }
- //init query list
- struct query_list *qlist=NULL;
- if((qlist=(struct query_list *)malloc(sizeof(struct query_list)))==NULL)
- {
- perror(strerror(errno));
- if (fclose(fp) != 0)
- {
- perror("Error: unable to close datafile\n");
- return (-1);
- }
- return -1;
- }
- LL_INIT(&qlist->query_list_head);
- int j=0;
- //read file finish flag
- int got_eof = 0;
- int thread_i=0;
- //thread pool
- pthread_t *pids=(pthread_t *)malloc(max_thread*sizeof(pthread_t));
- memset(pids,0,max_thread*sizeof(pthread_t));
- while(got_eof==0)
- {
- int input_length = MAX_INPUT_LEN;
- char input_line[MAX_INPUT_LEN + 1]={0};
- int len = next_input_line(fp,input_line, input_length);
- if (len == 0)
- {
- //read file finish
- got_eof = 1;
- }else
- {
- char * domain=trim(input_line);
- if(strlen(domain)==0)
- {
- //skip empty line
- continue;
- }
- struct query_result *qr=addquery(qlist,domain);
- //multi_thread to resolv the domain
- if((pthread_create(&pids[thread_i],NULL,(void *) get_ip_list,(void *)qr))!=0)
- {
- printf ("Create pthread error!\n");
- exit (1);
- }
- thread_i++;
- if(thread_i >= max_thread)
- {
- for(j=0;j<max_thread;j++)
- {
- //waiting for all thread finish
- if(pids[j]!=0)
- {
- pthread_join(pids[j], NULL);
- pids[j]=0;
- }
- }
- //next loop
- thread_i=0;
- }
- }
- }
- //if exists unfinish thread wait
- for(j=0;j<max_thread;j++)
- {
- if(pids[j]!=0)
- {
- pthread_join(pids[j], NULL);
- pids[j]=0;
- }
- }
- free(pids);
- //output the result
- printResult(qlist);
- free(qlist);
- //close file
- if (fclose(fp) != 0)
- {
- perror("Error: unable to close datafile\n");
- return (-1);
- }
- return 0;
- }