连接Tracker模块的设计和实现
连接Tracker模块的主要功能是:构造HTTP请求,请求Tracker服务器发送peer的IP地址和端口号;与Tracker建立连接;解析从Tracker返回的数据。Tracker返回的数据是经过B编码的,解析Tracker的回应和解析种子文件是类似的。
本模块由tracker.h和tracker.c构成。
以下是tracker.h的代码:
#ifndef TRACKER_H
#define TRACKER_H
#include <netinet/in.h>
#include "parse_metafile.h"
typedef struct _Peer_addr {
char ip[16];
unsigned short port;
struct _Peer_addr *next;
} Peer_addr;
// 用于将info_hash和peer_id转换为http编码格式
// http协议规定,传输数据中的非数字和非字母都要进行编码转换
int http_encode(unsigned char *in,int len1,char *out,int len2);
// 从种子文件中存储的tracker的URL获取tracker主机名
int get_tracker_name(Announce_list *node,char *name,int len);
// 从种子文件中存储的tracker的URL获取tracker端口号
int get_tracker_port(Announce_list *node,unsigned short *port);
// 创建发送到tracker服务器的请求信息
int create_request(char *request, int len,Announce_list *node,
unsigned short port,long long down,long long up,
long long left,int numwant);
// 准备连接tracker
int prepare_connect_tracker(int *max_sockfd);
// 准备连接peer
int prepare_connect_peer(int *max_sockfd);
// 获取tracker返回的消息的类型
// 一种类型为"5:peers"关键字之后是一个字符串,另一种是一个列表
int get_response_type(char *buffer,int len,int *total_length);
// 解析第一种tracker返回的消息
int parse_tracker_response1(char *buffer,int ret,char *redirection,int len);
// 解析第二种tracker返回的消息
int parse_tracker_response2(char *buffer,int ret);
// 将与之建立连接的peer加入到peer列表中
int add_peer_node_to_peerlist(int *sock,struct sockaddr_in saptr);
void free_peer_addr_head();
// 释放本文件函数中动态分配的内存以防止内存泄漏
void release_memory_in_tracker();
#endif
tracker.c的文件的头部包含的代码如下:
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <errno.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include "parse_metafile.h"
#include "peer.h"
#include "tracker.h"
extern unsigned char info_hash[20];
extern unsigned char peer_id[20];
extern Announce_list *announce_list_head;
extern int *sock;
extern struct sockaddr_in *tracker;
extern int *valid;
extern int tracker_count;
extern int *peer_sock;
extern struct sockaddr_in *peer_addr;
extern int *peer_valid;
extern int peer_count;
Peer_addr *peer_addr_head = NULL;
tracker.c的函数的定义如下:
int http_encode(unsigned char *in, int len1, char *out, int len2)
/*
*功能:根据HTTP协议进行编码转换
*传入参数:
* *in
* len1
*传出参数:
* *out
* len2
*返回值:
* -1 错误
* 0
*/
int http_encode(unsigned char *in,int len1,char *out,int len2)
{
int i, j;
char hex_table[16] = "0123456789abcdef";
if( (len1 != 20) || (len2 <= 90) )
{
return -1;
}
for(i = 0, j = 0; i < 20; i++, j++)
{
if( isalpha(in[i]) || isdigit(in[i]) )
{//英文字符
out[j] = in[i];
}
else
{
out[j] = '%';
j++;
out[j] = hex_table[in[i] >> 4];//取出ASCII码的高四位
j++;
out[j] = hex_table[in[i] & 0xf];//取出ASCII码的低四位
}
}
out[j] = '\0';
#ifdef DEBUG
//printf("http encoded:%s\n",out);
#endif
return 0;
}
代码说明:进行编码转换,根据HTTP协议,HTTP请求中的非数字和非字母都有进行编码转换。例如:空格符既不属于0~9也不属于a~z、A~Z,需要进行转换,它的ASCII码为0x20,转换为字符串“%20”int get_tracker_name(Announce_list *node, char *name, int len)
/*
*功能:获取Tracker URL中的主机名