3.ok,在初步了解完这些系统调用后,我们就可以开始干活了。 A.开始定义头文件了。 #ifndef __ANT_H #define __ANT_H //定义包含库 #include #include
#include #include #include #include #include #include #include //定义蚂蚁的最大数目 #define MAXANTNUM 6 //定义缓存大小 #define BUFSIZE 1500 //从传进来的长字符串分别拣开文件名、域名、路径、端口等 #define FILENAME 1 #define SITENAME 2 #define PATHNAME 3 #define PORTNAME 4 typedef char URL[256]; //定义蚂蚁的数据结构 strUCt Ant{ int s; // URL mission; int position; int amount; char haversack[BUFSIZE]; int ready; }; //定义任务的数据结构 struct Mission{ char host[100]; u_short port; URL url; }; //是否用代理 0表示不用,1表示用 extern int use_proxy; //代理地址 extern char proxy_server[100]; //代理端口 extern u_short proxy_port; //蚂蚁数目 extern int ant_num; extern int bulk; //下载进度 extern int progress; //配置文件 extern char cfgfile[256]; //日志文件 extern char logfile[256]; extern struct Ant* ants[10]; extern struct Mission ms; //此函数是读取配置文件的 extern void read_cfg(char* file); //此函数是初始化环境的,给变量赋值 extern void init_env(); //分配下载任务 extern int assign_mission(FILE* log, struct Ant* ant); //此函数是去掉字符串的空格 extern void eat_whitespace(char* str); // extern char* extract_from_url(URL url,int what); //从日志文件中取得地址 extern char* get_url_from_log(FILE* log); //返回下载文件的大小 extern int get_size_of_url(struct Mission* pms); //go......下载文件 extern int go(struct Ant* ant, struct Mission* pms); extern void enroll(struct Ant* ant, fd_set* rset); extern void unenroll(struct Ant* ant,fd_set* rset); extern int receive(struct Ant* ant, FILE* save); //假如意外退出,保存当前状态 extern int save_status(struct Ant* ant, FILE* log); #endif B.在定义完头文件后,下面就可以写辅助函数了,主要是围绕着读取配置、创建连接、下载文件、保存文件、保存当前蚂蚁状态等。
下面就是funcs.c源码内容 #include "ant.h" //读取配置文件,并赋予相关变量的值 void read_cfg(char* cfgfile) { FILE* f; int i; char line[256]; char* p=(char*)NULL; //判定是否能打开该文件 if((f = fopen(cfgfile, "r")) == (FILE*)NULL){ printf("can not open cfg file "); exit(1); } while(fgets(line, 256, f)!=(char*)NULL){ eat_whitespace(line);//去掉空行(此喂自定义函数) if(line[0]=='#') continue; for(i = 0; line[i]; i++) line[i]=tolower(line[i]); //将所有字母转换成小写的 if((p = strstr(line,"use_proxy"))){ //查找代理(proxy)开关设置信息,有则给use_proxy=1,否则为0 if(strstr(line,"yes")) use_proxy=1; else use_proxy=0; } else if((p = strstr(line,"proxy_server"))){ //查找代理服务器地址设置信息,将值赋给(proxy_server) p=strstr(line,"="); eat_whitespace(++p); strcpy(proxy_server, p); } else if((p = strstr(line, "proxy_port"))){ //查找代理端口设置信息,将值赋给(proxy_port) p=strstr(line, "="); eat_whitespace(++p); proxy_port=atoi(p); } } } void //初始化环境参数,将值赋给各个变量 init_env( ) { strcpy(cfgfile, "./ant.conf"); //取得配置文件名 read_cfg(cfgfile); //取得配置文件中的变量 logfile[0] = cfgfile[0] = 0; ant_num = MAXANTNUM; bulk = 0; progress=0; } char* //从记录文件里取得URL地址,断点续传的时候用,函数返回url get_url_from_log(FILE* log) { static URL url; URL line; fseek(log, 0, SEEK_SET); //从文件中读取字符串,从起始字符为"#"的行取url while(fgets(line, sizeof(line)-1, log)!=(char*)NULL){ eat_whitespace(line); if(line[0]=='#') continue; strcpy(url, line); return url; } memset(url,0,sizeof(url)); //内存中为之分配地址 return url; } int //分配下载任务,失败返回0,从上面函数返回的字符中分析出将相关的值赋给数据结构ant assign_mission(FILE* log, struct Ant* ant) { char line[256]; char* p; while(fgets(line, 256, log)!=(char*)NULL){ eat_whitespace(line); if((line[0]=='#')toupper(line[0]=='H')toupper(line[0]=='F')) continue; if(isdigit(line[0])){ ant->position=atoi(line); p=index(line,':'); ant->amount=atoi(++p); return 1; }else continue; } return 0; } void //去掉字符流中的空行 eat_whitespace(char* str) { char* p; int i; p=str; for(i=0; isspace(p[i]); i++ ); for( ;*p ;p++) *p=p[i]; p=str; for(i=strlen(str)-1;isspace(p[i]);i--) p[i]=0; } char* //从传进来的url字符串中,分析出文件名、域名、端口名、路径, 根据不同的what返回不同的字串。 extract_from_url(URL url,int what) { static char res[100]; char* p; char* pn; res[0]=0; memset(res,0,100); switch (what){ case FILENAME://分析文件名、若没有用index.Html替代(网络默认的首页,呵呵) p=rindex(url,'/'); if((*(p-1)=='/')(*(p+1)==0)) strcpy(res,"index.html"); else strcpy(res,++p); break; case PATHNAME: break; case SITENAME: //分析出域名,其中,对FTP,和http做出分类 if((p=index(url, '@'))) p++; else{ if((p=strstr(url,"http://"))) p+=7; else if((p=strstr(url,"ftp://"))) p+=6; else p=url; } if((pn=index(p,':'))(pn=index(p,'/'))){ strncpy(res,p,pn-p); res[pn-p] = 0; } else strcpy(res,p); break; case PORTNAME: //在字符"www.XXXX.com:8080/"之间取得端口号 if((p=rindex(url,':'))&&(*(++p)!='/')){ if((pn=index(p,'/'))){ strncpy(res,p,pn-p); res[pn-p]=0; } else strcpy(res,p); } else{ strcpy(res,"80"); } break; } return res; } // int //根据传进来的Mission数据结构,建立socket链接,取得文件的大小。
get_size_of_url(struct Mission* pms) { int s; struct sockaddr_in sin; struct hostent* phe; char cmd[256]; char msg_hdr[1000]; char* p; //预备http中GET 方法的请求。 sprintf(cmd,"GET %s HTTP/1.0 ", pms->url); //创建socket if((s=socket(PF_INET,SOCK_STREAM,0))<0) return -1; //取得远程主机的IP地址,失败函数返回-1 if((phe = gethostbyname(pms->host)) == NULL) return -1; memset(&sin,0,sizeof(sin)); memcpy(&sin.sin_addr,phe->h_addr,sizeof(struct in_addr)); sin.sin_fa
|