用C语言开发一个BT下载软件 (四) ------ 代码实现-2-位图管理模块的代码实现
2017-12-29 18:49
821 查看
//bitfield.h
#ifndef BITFIELD_H
#define BITFIELD_H
//位图结构体
typedef struct _Bitmap {
unsigned char *bitfield; // 保存位图地址的指针
int bitfield_length; // 位图所占的总字节数
int valid_length; // 位图有效的总位数,每一位代表一个piece
/*比如,某位图占100字节,而有效位数是795,则位图最后一个字节的最后5位(100*8-795)是无效的*/
} Bitmap;
//函数
int create_bitfield(); // 创建位图,分配内存并进行初始化
int get_bit_value(Bitmap *bitmap,int index); // 获取某一位的值
int set_bit_value(Bitmap *bitmap,int index,
unsigned char value); // 设置某一位的值
int all_zero(Bitmap *bitmap); // 全部清零
int all_set(Bitmap *bitmap); // 全部设置为1
void release_memory_in_bitfield(); // 释放bitfield.c中动态分配的内存
int print_bitfield(Bitmap *bitmap); // 打印位图值,用于调试
int restore_bitmap(); // 将位图存储到文件中
// 在下次下载时,先读取该文件获取已经下载的进度
// 籍此可以实现“断点续传”
int is_interested(Bitmap *dst,Bitmap *src); // 拥有位图src的peer是否对拥有
// dst位图的peer感兴趣
int get_download_piece_num(); // 获取当前已下载到的总piece数
#endif
#ifndef BITFIELD_H
#define BITFIELD_H
//位图结构体
typedef struct _Bitmap {
unsigned char *bitfield; // 保存位图地址的指针
int bitfield_length; // 位图所占的总字节数
int valid_length; // 位图有效的总位数,每一位代表一个piece
/*比如,某位图占100字节,而有效位数是795,则位图最后一个字节的最后5位(100*8-795)是无效的*/
} Bitmap;
//函数
int create_bitfield(); // 创建位图,分配内存并进行初始化
int get_bit_value(Bitmap *bitmap,int index); // 获取某一位的值
int set_bit_value(Bitmap *bitmap,int index,
unsigned char value); // 设置某一位的值
int all_zero(Bitmap *bitmap); // 全部清零
int all_set(Bitmap *bitmap); // 全部设置为1
void release_memory_in_bitfield(); // 释放bitfield.c中动态分配的内存
int print_bitfield(Bitmap *bitmap); // 打印位图值,用于调试
int restore_bitmap(); // 将位图存储到文件中
// 在下次下载时,先读取该文件获取已经下载的进度
// 籍此可以实现“断点续传”
int is_interested(Bitmap *dst,Bitmap *src); // 拥有位图src的peer是否对拥有
// dst位图的peer感兴趣
int get_download_piece_num(); // 获取当前已下载到的总piece数
#endif
//bitfield.c #include <stdio.h> #include <unistd.h> #include <string.h> #include <malloc.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include "parse_metafile.h" #include "bitfield.h" extern int pieces_length; //parse_metafile.c中定义的全局变量 extern char *file_name; //在硬盘保存位图的文件名 Bitmap *bitmap = NULL; // 指向位图 int download_piece_num = 0; // 当前已下载的piece数 // 如果存在一个位图文件,则读位图文件并把获取的内容保存到内存中的bitmap // 如此一来,就可以实现断点续传,即上次下载的内容不至于丢失 int create_bitfield() { bitmap = (Bitmap *)malloc(sizeof(Bitmap)); if(bitmap == NULL) { printf("allocate memory for bitmap fiailed\n"); return -1; } // pieces_length除以20即为总的piece数 bitmap->valid_length = pieces_length / 20; bitmap->bitfield_length = pieces_length / 20 / 8; if( (pieces_length/20) % 8 != 0 ) bitmap->bitfield_length++; bitmap->bitfield = (unsigned char *)malloc(bitmap->bitfield_length); if(bitmap->bitfield == NULL) { printf("allocate memory for bitmap->bitfield fiailed\n"); if(bitmap != NULL) free(bitmap); return -1; } char bitmapfile[64]; sprintf(bitmapfile,"%dbitmap",pieces_length); int i; FILE *fp = fopen(bitmapfile,"rb"); if(fp == NULL) { // 若打开文件失败,说明开始的是一个全新的下载 memset(bitmap->bitfield, 0, bitmap->bitfield_length); } else { fseek(fp,0,SEEK_SET); for(i = 0; i < bitmap->bitfield_length; i++) (bitmap->bitfield)[i] = fgetc(fp); fclose(fp); // 给download_piece_num赋新的初值 download_piece_num = get_download_piece_num(); } return 0; } // 获取位图中某一位的值,即某个piece已下载(1)或尚未下载(0) int get_bit_value(Bitmap *bitmap,int index) { int ret; int byte_index; unsigned char byte_value; unsigned char inner_byte_index; if(index >= bitmap->valid_length) return -1; byte_index = index / 8; byte_value = bitmap->bitfield[byte_index]; inner_byte_index = index % 8; byte_value = byte_value >> (7 - inner_byte_index); if(byte_value % 2 == 0) ret = 0; else ret = 1; return ret; } // 设置位图中某一位的值 int set_bit_value(Bitmap *bitmap,int index,unsigned char v) { int byte_index; unsigned char inner_byte_index; if(index >= bitmap->valid_length) return -1; if((v != 0) && (v != 1)) return -1; byte_index = index / 8; inner_byte_index = index % 8; v = v << (7 - inner_byte_index); bitmap->bitfield[byte_index] = bitmap->bitfield[byte_index] | v; return 0; } // 将位图所有位清0 int all_zero(Bitmap *bitmap) { if(bitmap->bitfield == NULL) return -1; memset(bitmap->bitfield,0,bitmap->bitfield_length); return 0; } //将位图所有位设置为1 int all_set(Bitmap *bitmap) { if(bitmap->bitfield == NULL) return -1; memset(bitmap->bitfield,0xff,bitmap->bitfield_length); return 0; } //释放本模块所申请的动态内存 void release_memory_in_bitfield() { if(bitmap->bitfield != NULL) free(bitmap->bitfield); if(bitmap != NULL) free(bitmap); } //打印位图(用于调试程序) int print_bitfield(Bitmap *bitmap) { int i; for(i = 0; i < bitmap->bitfield_length; i++) { printf("%.2X ",bitmap->bitfield[i]); if( (i+1) % 16 == 0) printf("\n"); } printf("\n"); return 0; } //保存位图,用于断点续传 int restore_bitmap() { int fd; char bitmapfile[64]; if( (bitmap == NULL) || (file_name == NULL) ) return -1; sprintf(bitmapfile,"%dbitmap",pieces_length); fd = open(bitmapfile,O_RDWR|O_CREAT|O_TRUNC,0666); if(fd < 0) return -1; write(fd,bitmap->bitfield,bitmap->bitfield_length); close(fd); return 0; } //判断拥有src位图的peer对拥有dst位图的peer是否感兴趣 int is_interested(Bitmap *dst,Bitmap *src) { unsigned char const_char[8] = { 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; unsigned char c1, c2; int i, j; if( dst==NULL || src==NULL ) return -1; if( dst->bitfield==NULL || src->bitfield==NULL ) return -1; if( dst->bitfield_length!=src->bitfield_length || dst->valid_length!=src->valid_length ) return -1; //如果dst中某位为1而src对应为0,则说明src对dst感兴趣 for(i = 0; i < dst->bitfield_length-1; i++) { for(j = 0; j < 8; j++) { //比较某个字节的所有位 c1 = (dst->bitfield)[i] & const_char[j]; c2 = (src->bitfield)[i] & const_char[j]; if(c1>0 && c2==0) return 1; } } j = dst->valid_length % 8; c1 = dst->bitfield[dst->bitfield_length-1]; c2 = src->bitfield[src->bitfield_length-1]; for(i = 0; i < j; i++) { //比较位图的最后一个字节 if( (c1&const_char[i])>0 && (c2&const_char[i])==0 ) return 1; } return 0; } /* 以上函数的功能测试代码如下: 测试时可以交换map1.bitfield和map2.bitfield的值或赋其他值 Bitmap map1, map2; unsigned char bf1[2] = { 0xa0, 0xa0 }; unsigned char bf2[2] = { 0xe0, 0xe0 }; map1.bitfield = bf1; map1.bitfield_length = 2; map1.valid_length = 11; map2.bitfield = bf2; map2.bitfield_length = 2; map2.valid_length = 11; int ret = is_interested(&map1,&map2); printf("%d\n",ret); */ // 获取当前已下载到的总的piece数 int get_download_piece_num() { //此处为什么用以下这个数组,而不直接判断某个位是否是1,是1则download_piece_num递增即可??? unsigned char const_char[8] = { 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; // 128 64 32 16 8 4 2 1 int i, j; if(bitmap==NULL || bitmap->bitfield==NULL) return 0; download_piece_num =0; for(i = 0; i < bitmap->bitfield_length-1; i++) { for(j = 0; j < 8; j++) { if( ((bitmap->bitfield)[i] & const_char[j]) != 0) download_piece_num++; } } unsigned char c = (bitmap->bitfield)[i]; // c存放位图最后一个字节 j = bitmap->valid_length % 8; // j是位图最后一个字节的有效位数 for(i = 0; i < j; i++) { if( (c & const_char[i]) !=0 ) download_piece_num++; } return download_piece_num; }
相关文章推荐
- 用C语言开发一个BT下载软件 (四) ------ 代码实现-5-Peer管理模块
- 用C语言开发一个BT下载软件 (四) ------ 代码实现-4-信号处理模块
- 用C语言开发一个BT下载软件 (四) ------ 代码实现-3-出错处理模块和运行日志模块
- 用C语言开发一个BT下载软件 (四) ------ 代码实现-1-种子文件解析模块
- 用C语言开发一个BT下载软件(一) ------ BitTorrent协议 -2
- 用C语言开发一个BT下载软件(一) ------ BitTorrent协议 -1
- BT下载软件开发笔记——种子解析模块的设计与实现
- 用C语言开发一个BT下载软件 (二) ------ 算法和策略
- 用C语言开发一个BT下载软件 (三) ------ 系统结构设计
- Java语言实现简单FTP软件 FTP上传下载管理模块实现(11)
- Linux平台下基于BitTorrent应用层协议的下载软件开发--日志管理模块(log.h)
- Linux平台下基于BitTorrent应用层协议的下载软件开发--缓冲管理模块(data.c)
- 概述 RequireJS是一个工具库,主要用于客户端的模块管理。它可以让客户端的代码分成一个个模块,实现异步或动态加载,从而提高代码的性能和可维护性。它的模块管理遵守AMD规范(Asynchronou
- Eclipse SWT开发教程以及一个连连看游戏的代码实现下载
- 基于GTK+3 开发远程控制管理软件(C语言实现)系列二 Centos7下开发环境搭建
- 基于GTK+3 开发远程控制管理软件(C语言实现)系列三 Windows7开发环境搭建
- Linux平台下基于BitTorrent应用层协议的下载软件开发--日志管理模块(log.c)
- Linux BT下载(9)-位图管理模块的设计和实现
- android中的sqlit3数据库进行手机应用软件开发(自写的一个财务管理软件,这里主要讲收入录入模块)
- Linux平台下基于BitTorrent应用层协议的下载软件开发--位图模块(bitfield.h)