从0实现 BT 下载 :2 Tracker 服务交互
在上一篇 1种子的解析 介绍了种子的解析,已经可以解析出来关键的信息了:
announce list: Tracker 服务器列表
info_hash:文件 SHA1 20Byte 经过 URL 编码
peer_id:客户标识
先看一个真实请求样例:
* example
curl -v "http://share.camoe.cn:8080/announce?info_hash=%87%2F%DF%A8K%97%B5%EC%7B%A6h%CA%B5%FF%28%40%FEK%22%0F&peer_id=%2DSD0100%2D%7Ef%5C%C5%1D%0E%A0%FEj%C3%C6%E5&ip=172.16.18.152&port=8797&uploaded=31354&downloaded=0&left=378440308&numwant=200&key=202&compact=1&event=started"
协议分为3种:udp http https ,udp 先不考虑实现,http https 2个都要实现的话,用 libcurl 是最为简单的,如果仅实现 http 使用纯 socket 也可以,https 如果不使用 libcurl 就必然用到 ssl 库。所以综合考虑还是先使用 libcurl 实现,当然后期想移除也可以。
思路是这样的:
解析完种子以后,循环每个 Tracker 分别调用 http 请求方法,多线程并发调用 ,有响应的 Tracker 服务器,将结果 回调通知出来,在统一做解析处理。
运行后结果如下:
已经可以得到 响应了,接下来就是解析处理
winhex 打开 不能在用 notepad++ 了容易产生误判
关键字段:
#pragma pack(push) #pragma pack(1) typedef struct peer_t { unsigned char ip[4]; unsigned char port[2]; } peer_t; #pragma pack(pop) int complete; //下载完成的 int incomplete; //正在下载的 int downloaded; //下载完成的 int interval; //下次请求时间 int min_interval; //最小请求时间限制 int peers; //客户端ip port 列表 用上面的 结构体解析 注意字节对齐
解析出来 结果
void Tracker::peersDecode(const char *buff, int len) { int i = 0; std::string ip = ""; int port = 0; peer_t *peer = (peer_t *)buff; LOG_DEBUG("buff:%s len:%d", buff, len); i = len / sizeof(*peer); while ( i-- ) { if ( peer && peer->ip && peer->port ) { ip = inetNtoaString(peer->ip); memcpy(&port, peer->port, sizeof(peer->port)); LOG_DEBUG("peers ip:%s port:%d", ip.c_str(), ntohs(port)); } peer++; } }
std::string inetNtoaString(const unsigned char *buff) { struct in_addr addr = { 0 }; if ( ! buff ) { return ""; } memcpy(&addr, buff, sizeof(addr)); return inet_ntoa(addr); }
其它网络模形:
UDP 协议 Tracker 服务器 待实现
DHT 协议 待实现