📄 policy.c
字号:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "parse_metafile.h"
#include "peer.h"
#include "data.h"
#include "message.h"
#include "policy.h"
Unchoke_peers unchoke_peers;
long long total_down = 0L, total_up = 0L;
float total_down_rate = 0.0F, total_up_rate = 0.0F;
int total_peers = 0;
extern int end_mode;
extern Bitmap *bitmap;
extern Peer *peer_head;
extern int pieces_length;
extern int piece_length;
extern Btcache *btcache_head;
extern int last_piece_index;
extern int last_piece_count;
extern int last_slice_len;
extern int download_piece_num;
// 初始化全局变量unchoke_peers
void init_unchoke_peers()
{
int i;
for(i = 0; i < UNCHOKE_COUNT; i++) {
*(unchoke_peers.unchkpeer + i) = NULL;
}
unchoke_peers.count = 0;
unchoke_peers.optunchkpeer = NULL;
}
// 判断一个peer是否已经存在于unchoke_peers
int is_in_unchoke_peers(Peer *node)
{
int i;
for(i = 0; i < unchoke_peers.count; i++) {
if( node == (unchoke_peers.unchkpeer)[i] ) return 1;
}
return 0;
}
// 从unchoke_peers中获取下载速度最慢的peer的索引
int get_last_index(Peer **array,int len)
{
int i, j = -1;
if(len <= 0) return j;
else j = 0;
for(i = 0; i < len; i++)
if( array[i]->down_rate < array[j]->down_rate ) j = i;
return j;
}
// 找出当前下载速度最快的4个peer,将其unchoke
int select_unchoke_peer()
{
Peer* p;
Peer* now_fast[UNCHOKE_COUNT];
Peer* force_choke[UNCHOKE_COUNT];
int unchoke_socket[UNCHOKE_COUNT], choke_socket[UNCHOKE_COUNT];
int i, j, index = 0, len = UNCHOKE_COUNT;
for(i = 0; i < len; i++) {
now_fast[i] = NULL;
force_choke[i] = NULL;
unchoke_socket[i] = -1;
choke_socket[i] = -1;
}
// 将那些在过去10秒已断开连接而又处于unchoke队列中的peer清除出unchoke队列
for(i = 0, j = 0; i < unchoke_peers.count; i++) {
p = peer_head;
while(p != NULL) {
if(p == unchoke_peers.unchkpeer[i]) break;
p = p->next;
}
if(p == NULL) { unchoke_peers.unchkpeer[i] = NULL; j++; }
}
if(j != 0) {
unchoke_peers.count = unchoke_peers.count - j;
for(i = 0, j = 0; i < len; i++) {
if(unchoke_peers.unchkpeer[i] != NULL) {
force_choke[j] = unchoke_peers.unchkpeer[i];
j++;
}
}
for(i = 0; i < len; i++) {
unchoke_peers.unchkpeer[i] = force_choke[i];
force_choke[i] = NULL;
}
}
// 将那些在过去10秒上传速度超过20KB/S而下载速度过小的peer强行阻塞
// 注意:up_rate和down_rate的单位是B/S而不是KB/S
for(i = 0, j = -1; i < unchoke_peers.count; i++) {
if( (unchoke_peers.unchkpeer)[i]->up_rate > 50*1024 &&
(unchoke_peers.unchkpeer)[i]->down_rate < 0.1*1024 ) {
j++;
force_choke[j] = unchoke_peers.unchkpeer[i];
}
}
// 从当前所有Peer中选出下载速度最快的四个peer
p = peer_head;
while(p != NULL) {
if(p->state==DATA && is_interested(bitmap,&(p->bitmap)) && is_seed(p)!=1) {
// p不应该在force_choke数组中
for(i = 0; i < len; i++) {
if(p == force_choke[i]) break;
}
if(i == len) {
if( index < UNCHOKE_COUNT ) {
now_fast[index] = p;
index++;
} else {
j = get_last_index(now_fast,UNCHOKE_COUNT);
if(p->down_rate >= now_fast[j]->down_rate) now_fast[j] = p;
}
}
}
p = p->next;
}
// 假设now_fast中所有的peer都是要unchoke的
for(i = 0; i < index; i++) {
Peer* q = now_fast[i];
unchoke_socket[i] = q->socket;
}
// 假设unchoke_peers.unchkpeer中所有peer都是choke的
for(i = 0; i < unchoke_peers.count; i++) {
Peer* q = (unchoke_peers.unchkpeer)[i];
choke_socket[i] = q->socket;
}
// 如果now_fast某个元素已经存在于unchoke_peers.unchkpeer
// 则没有必要进行choke或unckoke
for(i = 0; i < index; i++) {
if( is_in_unchoke_peers(now_fast[i]) == 1) {
for(j = 0; j < len; j++) {
Peer* q = now_fast[i];
if(q->socket == unchoke_socket[i]) unchoke_socket[i] = -1;
if(q->socket == choke_socket[i]) choke_socket[i] = -1;
}
}
}
// 更新当前unchoke的peer
for(i = 0; i < index; i++) {
(unchoke_peers.unchkpeer)[i] = now_fast[i];
}
unchoke_peers.count = index;
// 状态变化后,要对peer的状态值重新赋值,并且创建choke、unchoke消息
p = peer_head;
while(p != NULL) {
for(i = 0; i < len; i++) {
if(unchoke_socket[i]==p->socket && unchoke_socket[i]!=-1) {
p->am_choking = 0;
create_chock_interested_msg(1,p);
}
if(choke_socket[i]==p->socket && unchoke_socket[i]!=-1) {
p->am_choking = 1;
cancel_requested_list(p);
create_chock_interested_msg(0,p);
}
}
p = p->next;
}
//for(i = 0; i < unchoke_peers.count; i++)
// printf("unchoke peer:%s \n",(unchoke_peers.unchkpeer)[i]->ip);
return 0;
}
// 假设要下载的文件共有100个piece
// 以下函数的功能是将0到99这100个数的顺序以随机的方式打乱
// 从而得到一个随机的数组,该数组以随机的方式存储0~99,供片断选择算法使用
int *rand_num = NULL;
int get_rand_numbers(int length)
{
int i, index, piece_count, *temp_num;
if(length == 0) return -1;
piece_count = length;
rand_num = (int *)malloc(piece_count * sizeof(int));
if(rand_num == NULL) return -1;
temp_num = (int *)malloc(piece_count * sizeof(int));
if(temp_num == NULL) return -1;
for(i = 0; i < piece_count; i++) temp_num[i] = i;
srand(time(NULL));
for(i = 0; i < piece_count; i++) {
index = (int)( (float)(piece_count-i) * rand() / (RAND_MAX+1.0) );
rand_num[i] = temp_num[index];
temp_num[index] = temp_num[piece_count-1-i];
}
if(temp_num != NULL) free(temp_num);
return 0;
}
// 从peer队列中选择一个优化非阻塞peer
int select_optunchoke_peer()
{
int count = 0, index, i = 0, j, ret;
Peer *p = peer_head;
// 获取peer队列中peer的总数
while(p != NULL) {
count++;
p = p->next;
}
// 如果peer总数太少(小于等于4),则没有必要选择优化非阻塞peer
if(count <= UNCHOKE_COUNT) return 0;
ret = get_rand_numbers(count);
if(ret < 0) {
printf("%s:%d get rand numbers error\n",__FILE__,__LINE__);
return -1;
}
while(i < count) {
// 随机选择一个数,该数在0~count-1之间
index = rand_num[i];
p = peer_head;
j = 0;
while(j < index && p != NULL) {
p = p->next;
j++;
}
if( is_in_unchoke_peers(p) != 1 && is_seed(p) != 1 && p->state == DATA &&
p != unchoke_peers.optunchkpeer && is_interested(bitmap,&(p->bitmap)) ) {
if( (unchoke_peers.optunchkpeer) != NULL ) {
Peer *temp = peer_head;
while( temp != NULL ) {
if(temp == unchoke_peers.optunchkpeer) break;
temp = temp->next;
}
if(temp != NULL) {
(unchoke_peers.optunchkpeer)->am_choking = 1;
create_chock_interested_msg(0,unchoke_peers.optunchkpeer);
}
}
p->am_choking = 0;
create_chock_interested_msg(1,p);
unchoke_peers.optunchkpeer = p;
//printf("*** optunchoke:%s ***\n",p->ip);
break;
}
i++;
}
if(rand_num != NULL) { free(rand_num); rand_num = NULL; }
return 0;
}
// 计算最近一段时间(如10秒)每个peer的上传下载速度
int compute_rate()
{
Peer *p = peer_head;
time_t time_now = time(NULL);
long t = 0;
while(p != NULL) {
if(p->last_down_timestamp == 0) {
p->down_rate = 0.0f;
p->down_count = 0;
} else {
t = time_now - p->last_down_timestamp;
if(t == 0) printf("%s:%d time is 0\n",__FILE__,__LINE__);
else p->down_rate = p->down_count / t;
p->down_count = 0;
p->last_down_timestamp = 0;
}
if(p->last_up_timestamp == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -