📄 data.c
字号:
return 0;
}
// 将16MB缓冲区中已下载的piece写入硬盘,这样可以释放缓冲区
int write_btcache_to_harddisk(Peer *peer)
{
Btcache *p = btcache_head;
int slice_count = piece_length / (16*1024);
int index_count = 0;
int full_count = 0;
int first_index;
while(p != NULL) {
if(index_count % slice_count == 0) {
full_count = 0;
first_index = index_count;
}
if( (p->in_use == 1) && (p->read_write == 1) &&
(p->is_full == 1) && (p->is_writed == 0) ) {
full_count++;
}
if(full_count == slice_count) {
write_piece_to_harddisk(first_index,peer);
}
index_count++;
p = p->next;
}
return 0;
}
// 当缓冲区不够用时,释放那些从硬盘上读取的piece
int release_read_btcache_node(int base_count)
{
Btcache *p = btcache_head;
Btcache *q = NULL;
int count = 0;
int used_count = 0;
int slice_count = piece_length / (16*1024);
if(base_count < 0) return -1;
while(p != NULL) {
if(count % slice_count == 0) { used_count = 0; q = p; }
if(p->in_use==1 && p->read_write==0) used_count += p->access_count;
if(used_count == base_count) break; // 找到一个空闲的piece
count++;
p = p->next;
}
if(p != NULL) {
p = q;
while(slice_count > 0) {
p->index = -1;
p->begin = -1;
p->length = -1;
p->in_use = 0;
p->read_write = -1;
p->is_full = 0;
p->is_writed = 0;
p->access_count = 0;
slice_count--;
p = p->next;
}
}
return 0;
}
// 下载完一个slice后,检查是否该slice为一个piece最后一块
// 若是则写入硬盘,只对刚刚开始下载时起作用,这样可以立即使peer得知
int is_a_complete_piece(int index, int *sequnce)
{
Btcache *p = btcache_head;
int slice_count = piece_length / (16*1024);
int count = 0;
int num = 0;
int complete = 0;
while(p != NULL) {
if( count%slice_count==0 && p->index!=index ) {
num = slice_count;
while(num>0 && p!=NULL) { p = p->next; num--; count++; }
continue;
}
if( count%slice_count!=0 || p->read_write!=1 || p->is_full!=1)
break;
*sequnce = count;
num = slice_count;
while(num>0 && p!=NULL) {
if(p->index==index && p->read_write==1 && p->is_full==1)
complete++;
else break;
num--;
p = p->next;
}
break;
}
if(complete == slice_count) return 1;
else return 0;
}
// 将16MB的缓冲区中所存的所有数据清空
void clear_btcache()
{
Btcache *node = btcache_head;
while(node != NULL) {
node->index = -1;
node->begin = -1;
node->length = -1;
node->in_use = 0;
node->read_write = -1;
node->is_full = 0;
node->is_writed = 0;
node->access_count = 0;
node = node->next;
}
}
// 将从peer处获取的一个slice存储到缓冲区中
int write_slice_to_btcache(int index,int begin,int length,
unsigned char *buff,int len,Peer *peer)
{
int count = 0, slice_count, unuse_count;
Btcache *p = btcache_head, *q = NULL; // q指向每个piece第一个slice
if(p == NULL) return -1;
if(index>=pieces_length/20 || begin>piece_length-16*1024) return -1;
if(buff==NULL || peer==NULL) return -1;
if(index == last_piece_index) {
write_slice_to_last_piece(index,begin,length,buff,len,peer);
return 0;
}
if(end_mode == 1) {
if( get_bit_value(bitmap,index) == 1 ) return 0;
}
// 遍历缓冲区,检查当前slice所在的piece的其他数据是否已存在
// 若存在说明不是一个新的piece,若不存在说明是一个新的piece
slice_count = piece_length / (16*1024);
while(p != NULL) {
if(count%slice_count == 0) q = p;
if(p->index==index && p->in_use==1) break;
count++;
p = p->next;
}
// p非空说明当前slice所在的piece的有些数据已经下载
if(p != NULL) {
count = begin / (16*1024); // count存放当前要存的slice在piece中的索引
p = q;
while(count > 0) { p = p->next; count--; }
if(p->begin==begin && p->in_use==1 && p->read_write==1 && p->is_full==1)
return 0; // 该slice已存在
p->index = index;
p->begin = begin;
p->length = length;
p->in_use = 1;
p->read_write = 1;
p->is_full = 1;
p->is_writed = 0;
p->access_count = 0;
memcpy(p->buff,buff,len);
printf("+++++ write a slice to btcache index:%-6d begin:%-6x +++++\n",
index,begin);
// 如果是刚刚开始下载(下载到的piece不足10个),则立即写入硬盘,并告知peer
if(download_piece_num < 1000) {
int sequece;
int ret;
ret = is_a_complete_piece(index,&sequece);
if(ret == 1) {
printf("###### begin write a piece to harddisk ######\n");
write_piece_to_harddisk(sequece,peer);
printf("###### end write a piece to harddisk ######\n");
}
}
return 0;
}
// p为空说明当前slice是其所在的piece的第一块下载到的数据
// 首先判断是否存在空的缓冲区,若不存在,则将已下载的写入硬盘
int i = 4;
while(i > 0) {
slice_count = piece_length / (16*1024);
count = 0; // 计数当前指向第几个slice
unuse_count = 0; // 计数当前piece中有多少个空的slice
Btcache *q;
p = btcache_head;
while(p != NULL) {
if(count%slice_count == 0) { unuse_count = 0; q = p; }
if(p->in_use == 0) unuse_count++;
if(unuse_count == slice_count) break; // 找到一个空闲的piece
count++;
p = p->next;
}
if(p != NULL) {
p = q;
count = begin / (16*1024);
while(count > 0) { p = p->next; count--; }
p->index = index;
p->begin = begin;
p->length = length;
p->in_use = 1;
p->read_write = 1;
p->is_full = 1;
p->is_writed = 0;
p->access_count = 0;
memcpy(p->buff,buff,len);
printf("+++++ write a slice to btcache index:%-6d begin:%-6x +++++\n",
index,begin);
return 0;
}
if(i == 4) write_btcache_to_harddisk(peer);
if(i == 3) release_read_btcache_node(16);
if(i == 2) release_read_btcache_node(8);
if(i == 1) release_read_btcache_node(0);
i--;
}
// 如果还没有空闲的缓冲区,丢弃下载到这个slice
printf("+++++ write a slice to btcache FAILED :NO BUFFER +++++\n");
clear_btcache();
return 0;
}
// 从缓冲区获取一个slice,读取的slice存放到buff指向的数组中
// 若缓冲区中不存在该slice,则从硬盘读slice所在的piece到缓冲区中
int read_slice_for_send(int index,int begin,int length,Peer *peer)
{
Btcache *p = btcache_head, *q; // q指向每个piece第一个slice
int ret;
// 检查参数是否有误
if(index>=pieces_length/20 || begin>piece_length-16*1024) return -1;
ret = get_bit_value(bitmap,index);
if(ret < 0) { printf("peer requested slice did not download\n"); return -1; }
if(index == last_piece_index) {
read_slice_for_send_last_piece(index,begin,length,peer);
return 0;
}
// 待获取得slice缓冲区中已存在
while(p != NULL) {
if(p->index==index && p->begin==begin && p->length==length &&
p->in_use==1 && p->is_full==1) {
// 构造piece消息
ret = create_piece_msg(index,begin,p->buff,p->length,peer);
if(ret < 0) { printf("Function create piece msg error\n"); return -1; }
p->access_count = 1;
return 0;
}
p = p->next;
}
int i = 4, count, slice_count, unuse_count;
while(i > 0) {
slice_count = piece_length / (16*1024);
count = 0; // 计数当前指向第几个slice
p = btcache_head;
while(p != NULL) {
if(count%slice_count == 0) { unuse_count = 0; q = p; }
if(p->in_use == 0) unuse_count++;
if(unuse_count == slice_count) break; // 找到一个空闲的piece
count++;
p = p->next;
}
if(p != NULL) {
read_piece_from_harddisk(q,index);
p = q;
while(p != NULL) {
if(p->index==index && p->begin==begin && p->length==length &&
p->in_use==1 && p->is_full==1) {
// 构造piece消息
ret = create_piece_msg(index,begin,p->buff,p->length,peer);
if(ret < 0) { printf("Function create piece msg error\n"); return -1; }
p->access_count = 1;
return 0;
}
p = p->next;
}
}
if(i == 4) write_btcache_to_harddisk(peer);
if(i == 3) release_read_btcache_node(16);
if(i == 2) release_read_btcache_node(8);
if(i == 1) release_read_btcache_node(0);
i--;
}
// 如果实在没有缓冲区了,就不读slice所在的piece到缓冲区中
p = initialize_btcache_node();
if(p == NULL) { printf("%s:%d allocate memory error",__FILE__,__LINE__); return -1; }
p->index = index;
p->begin = begin;
p->length = length;
read_slice_from_harddisk(p);
// 构造piece消息
ret = create_piece_msg(index,begin,p->buff,p->length,peer);
if(ret < 0) { printf("Function create piece msg error\n"); return -1; }
// 释放刚刚申请的内存
if(p->buff != NULL) free(p->buff);
if(p != NULL) free(p);
return 0;
}
void clear_btcache_before_peer_close(Peer *peer)
{
Request_piece *req = peer->Request_piece_head;
int i = 0, index[2] = {-1, -1};
if(req == NULL) return;
while(req != NULL && i < 2) {
if(req->index != index[i]) { index[i] = req->index; i++; }
req = req->next;
}
Btcache *p = btcache_head;
while( p != NULL ) {
if( p->index != -1 && (p->index==index[0] || p->index==index[1]) ) {
p->index = -1;
p->begin = -1;
p->length = -1;
p->in_use = 0;
p->read_write = -1;
p->is_full = 0;
p->is_writed = 0;
p->access_count = 0;
}
p = p->next;
}
}
// 针对下载最后一个piece的问题,修改以下几处:
// 在data.c头部增加了几个全局变量
// 在data.c中修改了初始分配动态内存函数和最终释放动态内存的函数
// 在rate.c中修改了create_req_slice_msg函数
// 在data.c中增加了以下4个函数
int write_last_piece_to_btcache(Peer *peer)
{
int index = last_piece_index, i;
unsigned char piece_hash1[20], piece_hash2[20];
Btcache *p = last_piece;
// 校验piece的HASH值
SHA1_CTX ctx;
SHA1Init(&ctx);
while(p != NULL) {
SHA1Update(&ctx,p->buff,p->length);
p = p->next;
}
SHA1Final(piece_hash1,&ctx);
for(i = 0; i < 20; i++) piece_hash2[i] = pieces[index*20+i];
if(memcmp(piece_hash1,piece_hash2,20) == 0) {
printf("@@@@@@ last piece downlaod OK @@@@@@\n");
} else {
printf("@@@@@@ last piece downlaod NOT OK @@@@@@\n");
return -1;
}
p = last_piece;
while( p != NULL) {
write_btcache_node_to_harddisk(p);
p = p->next;
}
printf("@@@@@@ last piece write to harddisk OK @@@@@@\n");
// 在peer中的请求队列中删除piece请求
// 更新位图
set_bit_value(bitmap,index,1);
// 准备发送have消息
for(i = 0; i < 64; i++) {
if(have_piece_index[i] == -1) {
have_piece_index[i] = index;
break;
}
}
download_piece_num++;
if(download_piece_num % 10 == 0) restore_bitmap();
return 0;
}
int write_slice_to_last_piece(int index,int begin,int length,
unsigned char *buff,int len,Peer *peer)
{
if(index != last_piece_index || begin > (last_piece_count-1)*16*1024)
return -1;
if(buff==NULL || peer==NULL) return -1;
// 定位到要写入哪个slice
int count = begin / (16*1024);
Btcache *p = last_piece;
while(p != NULL && count > 0) {
count--;
p = p->next;
}
if(p->begin==begin && p->in_use==1 && p->is_full==1)
return 0; // 该slice已存在
p->index = index;
p->begin = begin;
p->length = length;
p->in_use = 1;
p->read_write = 1;
p->is_full = 1;
p->is_writed = 0;
p->access_count = 0;
memcpy(p->buff,buff,len);
p = last_piece;
while(p != NULL) {
if(p->is_full != 1) break;
p = p->next;
}
if(p == NULL) {
write_last_piece_to_btcache(peer);
}
return 0;
}
int read_last_piece_from_harddisk(Btcache *p, int index)
{
Btcache *node_ptr = p;
int begin = 0;
int length = 16*1024;
int slice_count = last_piece_count;
int ret;
if(p==NULL || index != last_piece_index) return -1;
while(slice_count > 0) {
node_ptr->index = index;
node_ptr->begin = begin;
node_ptr->length = length;
if(begin == (last_piece_count-1)*16*1024)
node_ptr->length = last_slice_len;
ret = read_slice_from_harddisk(node_ptr);
if(ret < 0) return -1;
node_ptr->in_use = 1;
node_ptr->read_write = 0;
node_ptr->is_full = 1;
node_ptr->is_writed = 0;
node_ptr->access_count = 0;
begin += 16*1024;
slice_count--;
node_ptr = node_ptr->next;
}
return 0;
}
int read_slice_for_send_last_piece(int index,int begin,int length,Peer *peer)
{
Btcache *p;
int ret, count = begin / (16*1024);
// 检查参数是否有误
if(index != last_piece_index || begin > (last_piece_count-1)*16*1024)
return -1;
ret = get_bit_value(bitmap,index);
if(ret < 0) {printf("peer requested slice did not download\n"); return -1;}
p = last_piece;
while(count > 0) {
p = p->next;
count --;
}
if(p->is_full != 1) {
ret = read_last_piece_from_harddisk(last_piece,index);
if(ret < 0) return -1;
}
if(p->in_use == 1 && p->is_full == 1) {
ret = create_piece_msg(index,begin,p->buff,p->length,peer);
}
if(ret == 0) return 0;
else return -1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -