在上一篇 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 协议 待实现