Linux BT下载(7)-种子解析模块设计与实现1
2016-11-26 13:42
417 查看
种子解析模块设计与实现
解析文件主要在parse_metafile.h和parse_metafile.c中实现。//parse_metafile.h 解析文件 #ifndef PARSE_METAFILE #define PARSE_METAFILE //保存种子文件中获取的tracker的URL typedef struct _Announce_list { char announce[128]; struct _Announce_list *next; } Announce_list; //保存各个待下载的文件的路径长度 typedef struct _Files { char path[256]; long length; struct _Files *next; } Files; int read_metafile(char *metafile_name); //读取种子文件 int find_keyword(char *keyword, long *position);//在种子文件中查找关键字 int read_announce_list(); //获取各个tracker服务器的地址 int add_an_announce(char *url); //向tracker列表添加一个url int get_piece_length(); //获取每个piece的长度,一般为256KB int get_pieces(); //获得各个piece的hash值 int is_multi_files(); //判断下载的是单个还是多个文件 int get_file_name(); //获取文件名,对于多文件获取的目录名 int get_file_length(); //获取待下载的文件总长度 int get_files_length_path();//获取文件的路径和长度,对多文件种子有效 int get_info_hash(); //由info关键词对应的值计算info_hash int get_peer_id(); //生成peer_id,每个peer都有一20字节的peer_id void release_memory_in_parse_metafile(); //释放parse_metafile.c中动态分配的内存 int parse_metafile(char *metafile); //调用本文件中定义的函数,完成解析种子文件 #endif
以下是parse_metafile.c文件的头部
//parse_metafile.c 解析文件 #include <stdio.h> #include <ctype.h> #include <malloc.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "parse_metafile.h" #include "shal.h" char *metafile_content = NULL; //保存种子的内容 long filesize; //种子的长度 int piece_length = 0; //每个piece的长度一般为256KB char *pieces = NULL; //保存每个pieces的hash值,每个为20B int pieces_length = 0; //缓冲区pieces的长度 int multi_file = 0; //指明是单文件还是多文件 char *file_name = NULL; //对于单文件,存放文件;对于多文件,存放目录名 long long file_length = 0; //存放待下载的文件的总长度 Files *files_head = NULL; //对多文件种子有效,存放各个文件的路径和长度 unsigned char info_hash[20]; //保存info_hash的值,连接tracker和peer时使用 unsigned char peer_id[20]; //保存peer_id的值,连接peer时使用 Announce_list *announce_list_head = NULL; //用于保存所有trackr的服务器的URL
具体函数如下:
int read_metafile(char *metafile_name),此函数的说明在代码中不再另写。
/* * int read_metafile(char *metafile_name) *解析种子文件 *metafile_name是种子文件名 *处理成功返回0,否则返回-1 *将种子文件的内容读入到全局变量metafile_content所指的缓存区中 *说明 编译器预定义的宏__FILE__和__LINE__在程序中可以直接使用。 *__FILE__代表该宏所在源文件的文件名,在源文件parse_metafile.c中 *该宏的值等于"parse_metafile.c",宏__LINE__的值为__LINE__所在的行 *号 * * */ int read_metafile(char *metafile_name) { long i; //以二进制、只读的方式打开文件 FILE *fp = fopen(metafile_name, "rb"); if(fp == NULL) { printf("%s:%d can not open file\n", __FILE__, __LINE__); return -1; } //获得种子文件的长度,fieszie为全局变量,在parse_metafile_name fseek(fp , 0, SEEK_END); filesize = ftell(fp); if(fileszie == -1) { printf("%s:%d fseek failed\n", __FILE__,__LINE__); return -1; } metafile_content = (char *)malloc(filesize+1); if(metafile_content == NULL) { printf("%s:%d malloc failed\n", __FILE__,__LINE__); return -1; } //读取种子文件的内容到metafile_content缓冲区中 fseek(fp, 0, SEEK_SET); for(i = 0; i < filesize; i++) { metafile_content[i] = fgetc(fp); } metafile_content[i] = '\0'; fclose(fp); #ifdef DEBUG printf("metafile size is: &ld\n", filesize); #endif return 0; }
int find_keyword(char *keyword,long *position)
/* int find_keyword(char *keyword, long *position) 功能:从种子文件中查找某个关键字 参数:keyword为要查找的关键字,position用于返回关键字第一个字符所在的下标. 返回:成功找到关键字返回1,未找到返回0,执行失败返回-1 */ int find_keyword(char *keyword, long *position) { long i; *position = -1; if(keyword == NULL) return 0; for(i = 0; i < filesize - strlen(keyword); i++) { if( memcmp(&metafile_content[i], keyword, strlen(keyword))==0) { *position = i; return 1; } } return 0; }
函数说明:此函数用于查找某个关键字(B编码的关键字)。例如:“8:announce”和“13:announce-list”之后是Tracker服务器的地址(URL),找到该关键字后,可以获取Tracker的地址。
int read_announce_list()
/* 功能:获得Tracker地址,并将获得的地址保存到全局变量announce_list_head指向的List中 */ int read_announce_list() { Announce_list *node = NULL; Announce_list *p = NULL; int len = 0; long i; if( find_keyword("13:announce-list", &i) == 0) {//无"13:announce-list"关键字 if( find_keyword("8:announce", &i) == 1) { //跳过"8:announce" i = i + strlen("8:announce"); //i未加前是字符串的起始位置 //检测字符串后边的字符是否是阿拉伯数字 //获取URL的长度 while(isdigit(metafile_content[i])) { len = len * 10 + (metafile_content[i] - '0'); i++; } i++; //跳过':' //申请堆空间保存Tracker的URL node = (Announce_list *)malloc(sizeof(Announce_list)); strcpy(node->announce, &metafile_content[i], len); node->announce[len] = '\0'; node->next = NULL; announce_list_head = node; } } else {/*如果有13:announce-list关键字不用处理8:announce关键词 **使用备用的URL(备用URL中包含关键字"8:announce"包含的URL) **关键字"13:announce-list"之后的第一个字符为列表的起始字符'l' **该列表中含有两个元素,这两个元素的类型也都是列表 ** */ i = i + strlen("13:announce-list"); i++; //跳过'1' while(metafile_content[i] != 'e') { i++; //跳过'l' /* *检查输入的参数是否为阿拉伯数字 *获取URL的长度 */ while(isdigit(metafile_content[i])) { len = len * 10 + (metafile_content[i] - '0'); i++; } if(metafile_content[i] == ':') i++; //跳过':' else return -1; //只处理以http开头的tracker地址,不处理以udp开头的地址 if(memcmp(&metafile_content[i], "http", 4) == 0) { node = (Announce_list *)malloc(sizeof(Announce_list)); strcpy(node->announce, &metafile_content[i],len); node->announce[len] = '\0'; node->next = NULL; if(announce_list_head == NULL) { announce_list_head = node; } else { p = announce_list_head; while(p->next != NULL) p = p->next; //使p指针指向最后个节点 p->next = node; //node成为tracker列表的最后一个节点 } } i = i + len; len = 0; i++; //跳过'e' if(i >= filesize) return -1; } //while循环结束 } #ifdef DEBUG p = announce_list_head; while(p != NULL) { printf("%s\n", p->announce); p = p->next; } #endif return 0; }
某种子文件的开头部分如下,可以帮助理解我的注释:
d8:announce32:http://tk.greedland.net/announce13:announce-listl132:http://tk.greedland.net/announcee113:http://th2.greedland.net/announceee...
第一个字符'd'是B编码中字典的起始符,接着是关键字“8:announce”,该关键字是长度为8的字符串,其对应的值为长度为32的字符串"32:http://tk.greedland,net/announce"是一个Tracker服务器地址(URL),接着是关键字"13:annunce-list",该关键字对应的是一个列表,应为关键字"13:announce-list"之后是第一个字符的起始字符"l",该列表中还有这两个元素的类型也都是列表。
如果有关键字"13:announce-list"哪吗就不用处理关键字"8:announce"的原因在于,前者对应的值必定包含对应的后者的值。
...
相关文章推荐
- Linux BT下载(8)-种子解析模块设计与实现2
- BT下载软件开发笔记——种子解析模块的设计与实现
- 解析大型.NET ERP系统 权限模块设计与实现
- 用C语言开发一个BT下载软件 (四) ------ 代码实现-1-种子文件解析模块
- 实现通用化DLL调用模块的设计解析
- Linux BT下载(14)-策略管理模块的设计和实现
- 常见设计模式的解析和实现(C++)之十三-FlyWeight模式
- 常见设计模式的解析和实现(C++)之十二-ChainOfResponsibility模式
- 常见设计模式的解析和实现(C++)之十六-Strategy模式
- 设计模式解析的C++实现
- 常见设计模式的解析和实现(C++)之四-Prototype模式
- 常见设计模式的解析和实现(C++)之十四-Command模式
- 常见设计模式的解析和实现(C++)之八-Composite模式
- 常见设计模式的解析和实现(C++)之二-Abstract Factory模式
- 常见设计模式的解析和实现(C++)之七-Bridge模式
- 常见设计模式的解析和实现(C++)之六-Adapt模式
- 常见设计模式的解析和实现(C++)之十一-TemplateMethod模式
- 常见设计模式的解析和实现(C++)之十八-Iterator模式
- 常见设计模式的解析和实现
- 常见设计模式的解析和实现(C++)之二十一-完结篇