您的位置:首页 > 编程语言 > C语言/C++

用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

//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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐