信号处理模块
本模块由signal_hander.h和signal_hander.c两个文件构成。
以下是signal_hander.h的代码:
// signal_hander.h
#ifndef SIGNAL_HANDER_H
#define SIGNAL_HANDER_H
// 做一些清理工作,如释放动态分配的内存
void do_clear_work();
// 处理一些信号
void process_signal(int signo);
// 设置信号处理函数
int set_signal_hander();
#endif
以下是signal_hander.c的代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include "signal_hander.h"
#include "parse_metafile.h"
#include "data.h"
#include "bitfield.h"
#include "peer.h"
#include "tracker.h"
#include "torrent.h"
extern int download_piece_num;
extern int *fds;
extern int fds_len;
extern Peer *peer_head;
/*
*功能:程序退出时,执行清理工作
*传入参数:
*传成参数:
*返回值:
*
*/
void do_clear_work()
{
// 关闭所有peer的socket
Peer *p = peer_head;
while(p != NULL)
{
if(p->state != CLOSING)
close(p->socket);
p = p->next;
}
// 保存位图
if(download_piece_num > 0)
{
restore_bitmap();
}
// 关闭文件描述符
int i;
for(i = 0; i < fds_len; i++)
{
close(fds[i]);
}
// 释放动态分配的内存
release_memory_in_parse_metafile();
release_memory_in_bitfield();
release_memory_in_btcache();
release_memory_in_peer();
release_memory_in_torrent();
exit(0);
}
void process_signal(int signo)
{
printf("Please wait for clear operations\n");
do_clear_work();
}
/*
*功能:信号处理函数
*传入参数:
*传成参数:
*返回值:
*
*/
int set_signal_hander()
{
if(signal(SIGPIPE,SIG_IGN) == SIG_ERR)
{
perror("can not catch signal:sigpipe\n");
return -1;
}
if(signal(SIGINT,process_signal) == SIG_ERR)
{
perror("can not catch signal:sigint\n");
return -1;
}
if(signal(SIGTERM,process_signal) == SIG_ERR)
{
perror("can not catch signal:sigterm\n");
return -1;
}
return 0;
}
Peer管理模块
系统为每一个与之建立TCP连接的Peer构造一个peer结构体。Peer管理模块负责管理由各个结点构成的Peer链表,主要工作是创建结点,添加结点到Peer链表,从Peer链表中删除结点等。
该模块由peer.h和peer.c组成。
以下是peer.h的代码:
// peer.h
#ifndef PEER_H
#define PEER_H
#include <string.h>
#include <time.h>
#include "bitfield.h"
#define INITIAL -1 // 表明处于初始化状态
#define HALFSHAKED 0 // 表明处于半握手状态
#define HANDSHAKED 1 // 表明处于全握手状态
#define SENDBITFIELD 2 // 表明处于已发送位图状态
#define RECVBITFIELD 3 // 表明处于已接收位图状态
#define DATA 4 // 表明处于与peer交换数据的状态
#define CLOSING 5 // 表明处于即将与peer断开的状态
// 发送和接收缓冲区的大小,16K可以存放一个slice,2K可以存放其他消息
#define MSG_SIZE 2*1024+16*1024
typedef struct _Request_piece
{
int index; // 请求的piece的索引
int begin; // 请求的piece的偏移
int length; // 请求的长度,一般为16KB
struct _Request_piece *next;
} Request_piece;
typedef struct _Peer
{
int socket; // 通过该socket与peer进行通信
char ip[16]; // peer的ip地址
unsigned short port; // peer的端口号
char id[21]; // peer的id
int state; // 当前所处的状态
int am_choking; // 是否将peer阻塞
int am_interested; // 是否对peer感兴趣
int peer_choking; // 是否被peer阻塞
int peer_interested; // 是否被peer感兴趣
Bitmap bitmap; // 存放peer的位图
char *in_buff; // 存放从peer处获取的消息
int buff_len; // 缓存区in_buff的长度
char *out_msg; // 存放将发送给peer的消息
int msg_len; // 缓冲区out_msg的长度
char *out_msg_copy; // out_msg的副本,发送时使用该缓冲区
int msg_copy_len; // 缓冲区out_msg_copy的长度
int msg_copy_index; // 下一次要发送的数据的偏移量
Request_piece *Request_piece_head; // 向peer请求数据的队列
Request_piece *Requested_piece_head; // 被peer请求数据的队列
unsigned int down_total; // 从该peer下载的数据的总和
unsigned int up_total; // 向该peer上传的数据的总和
time_t start_timestamp; // 最近一次接收到peer消息的时间
time_t recet_timestamp; // 最近一次发送消息给peer的时间
time_t last_down_timestamp; // 最近下载数据的开始时间
time_t last_up_timestamp; // 最近上传数据的开始时间
long long down_count; // 本计时周期从peer下载的数据的字节数
long long up_count; // 本计时周期向peer上传的数据的字节数
float down_rate; // 本计时周期从peer处下载数据的速度
float up_rate; // 本计时周期向peer处上传数据的速度
struct _Peer *next; // 指向下一个Peer结构体
} Peer;
int initialize_peer(Peer *peer); // 对peer进行初始化
Peer* add_peer_node(); // 添加一个peer结点
int del_peer_node(Peer *peer); // 删除一个peer结点
void free_peer_node(Peer *node); // 释放一个peer的内存
int cancel_request_list(Peer *node); // 撤消当前请求队列
int cancel_requested_list(Peer *node); // 撤消当前被请求队列
void release_memory_in_peer(); // 释放peer.c中的动态分配的内存
void print_peers_data(); // 打印peer链表中某些成员的值,用于调试
#endif
程序说明:(1)Peer结构体是整个程序最重要的数据结构,也是最负责的数据结构。peer.h定义了7中状态,各个状态转换图如下:
Peer结构体中定义两个发送缓冲区out_msg和out_msg_copy,将刚刚生成的消息暂存在out_msg中,调用套接字函数send向peer发送消息时使用out_msg_copy缓冲区。out_msg_copy缓冲区。out_msg_copy缓冲区的大小是18KB,而send函数一次最多发送1500字节,因此要使用msg_copy_index记录下次发送的数据的起始下标。事实上,send函数一次也可以发送超过1500字节的数据,不过若以这种方式发送导致发送数据混乱,具体原因将会解释。
peer.c文件的头部包含代码如下:
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include "peer.h"
#include "message.h"
#include "bitfield.h"
extern Bitmap *bitmap;
// 指向当前与之进行通信的peer列表
Peer *peer_head = NULL;
peer.c中各个函数的定义如下:
int initialize_peer(Peer *peer)
/*
*功能:出始化Peer结构体
*传入参数:Peer
*传出参数:无
*返回值:
* -1 失败
* 0 成功
*/
int initialize_peer(Peer *peer)
{
if(peer == NULL) return -1;
peer->socket = -1;
memset(peer->ip,0,16);
peer->port = 0;
memset(peer->id,0,21);
peer->state = INITIAL;
peer->in_buff = NULL;
peer->out_msg = NULL;
peer->out_msg_copy = NULL;
peer->in_buff = (char *)malloc(MSG_SIZE);
if(peer->in_buff == NULL) goto OUT;
memset(peer->in_buff,0,MSG_SIZE);
peer->buff_len = 0;
peer->out_msg = (char *)malloc(MSG_SIZE);
if(peer->out_msg == NULL) goto OUT;
memset(peer->out_msg,0,MSG_SIZE);
peer->msg_len = 0;
peer->out_msg_copy = (char *)malloc(MSG_SIZE);
if(peer->out_msg_copy == NULL) goto OUT;
memset(peer->out_msg_copy,0,MSG_SIZE);
peer->msg_copy_len = 0;
peer->msg_copy_index = 0;
peer->am_choking = 1;
peer->am_interested = 0;
peer->peer_choking = 1;
peer->peer_interested = 0;
peer->bitmap.bitfield = NULL;
peer->bitmap.bitfield_length = 0;
peer->bitmap.valid_length = 0;
peer->Request_piece_head = NULL;
peer->Requested_piece_head = NULL;
peer->down_total = 0;
peer->up_total = 0;
peer->start_timestamp = 0;
peer->recet_timestamp = 0;
peer->last_down_timestamp = 0;
peer->last_up_timestamp = 0;
peer->down_count = 0;
peer->up_count = 0;
peer->down_rate = 0.0;
peer->up_rate = 0.0;
peer->next = (Peer *)0;
return 0;
OUT:
if(peer->in_buff != NULL) free(peer->in_buff);
if(peer->out_msg != NULL) free(peer->out_msg);
if(peer->out_msg_copy != NULL) free(peer->out_msg_copy);
return -1;
}
Peer *add_peer_node()
/*
*功能:向peer链表添加一个结点
*传入参数:无
*传出参数:无
*返回值:
* NULL 失败
* 地址 成功
*/
Peer* add_peer_node()
{
int ret;
Peer *node, *p;
// 分配内存空间
node = (Peer *)malloc(sizeof(Peer));
if(node == NULL) {
printf("%s:%d error\n",__FILE__,__LINE__);
return NULL;
}
// 进行初始化
ret = initialize_peer(node);
if(ret < 0) {
printf("%s:%d error\n",__FILE__,__LINE__);
free(node);
return NULL;
}
// 将node加入到peer链表中
if(peer_head == NULL) { peer_head = node; }
else {
p = peer_head;
while(p->next != NULL) p = p->next;
p->next = node;
}
return node;
}
int del_peer_node(Peer *peer)
/*
*功能:从peer链表中删除一个结点
*传入参数:无
*传出参数:无
*返回值:
* -1 失败
* 0 成功
*/
int del_peer_node(Peer *peer)
{
Peer *p = peer_head, *q;
if(peer == NULL) return -1;
while(p != NULL) {
if( p == peer ) {
if(p == peer_head) peer_head = p->next;
else q->next = p->next;
free_peer_node(p); // 可能存在问题
return 0;
} else {
q = p;
p = p->next;
}
}
return -1;
}
int cancel_request_list(Peer *node)
/*
*功能:撤销当前请求队列
*传入参数:无
*传出参数:无
*返回值:
* 0 成功
*/
int cancel_request_list(Peer *node)
{
Request_piece *p;
p = node->Request_piece_head;
while(p != NULL) {
node->Request_piece_head = node->Request_piece_head->next;
free(p);
p = node->Request_piece_head;
}
return 0;
}
int cancel_requested_list(Peer *node)
/*
*功能:撤消当前被请求队列
*传入参数:无
*传出参数:无
*返回值:
* 0 成功
*/
//
int cancel_requested_list(Peer *node)
{
Request_piece *p;
p = node->Requested_piece_head;
while(p != NULL) {
node->Requested_piece_head = node->Requested_piece_head->next;
free(p);
p = node->Requested_piece_head;
}
return 0;
}
void free_peer_node(Peer *node)
/*
*功能:释放一个peer结点的内存
*传入参数:无
*传出参数:无
*返回值:
*/
void free_peer_node(Peer *node)
{
if(node == NULL) return;
if(node->bitmap.bitfield != NULL) {
free(node->bitmap.bitfield);
node->bitmap.bitfield = NULL;
}
if(node->in_buff != NULL) {
free(node->in_buff);
node->in_buff = NULL;
}
if(node->out_msg != NULL) {
free(node->out_msg);
node->out_msg = NULL;
}
if(node->out_msg_copy != NULL) {
free(node->out_msg_copy);
node->out_msg_copy = NULL;
}
cancel_request_list(node);
cancel_requested_list(node);
// 释放完peer成员的内存后,再释放peer所占的内存
free(node);
}
void release_memory_in_peer()
/*
*功能:释放peer管理模块中动态申请的内存
*传入参数:无
*传出参数:无
*返回值:
* NULL
*/
void release_memory_in_peer()
{
Peer *p;
if(peer_head == NULL) return;
p = peer_head;
while(p != NULL) {
peer_head = peer_head->next;
free_peer_node(p);
p = peer_head;
}
}
void print_peers_data()
/*
*功能:从peer链表中删除一个结点
*传入参数:无
*传出参数:无
*返回值:
* -1 失败
* 0 成功
*/
void print_peers_data()
{
Peer *p = peer_head;
int index = 0;
while(p != NULL) {
printf("peer: %d down_rate: %.2f \n", index, p->down_rate);
index++;
p = p->next;
}
}