fanpei91 / torsniff

torsniff - a sniffer that sniffs torrents from BitTorrent network

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

防止多个异步请求对同一个 infohash 进行 metadata 下载.

fanpei91 opened this issue · comments

比如 A 异步请求正在下载:

{
    infohash: 'e834c096cb8608b9fec9256ec4da8c7aad22d680',
    rinfo: {address: '192.168.1.1', port: 6881}
}

A 异步还没成功下载 metadata 或者还没下载完 metadata 的时候, 接着又来了 B 异步请求下载:

{
    infohash: 'e834c096cb8608b9fec9256ec4da8c7aad22d680', // 跟 A 异步请求的 infohash 一样.
    rinfo: {address: '192.168.3.1', port: 6882} // 跟 A 异步请求不一样
}

在未实现这个需求的时候, 程序是又会发起 B 异步请求去下载metadata, 这就显得多余(万一 A 请求最终能成功下载 metadata呢?)

那么, 需要一个机制, 不需要借助外部数据, 防止重复请求下载 metadata (即使借助了数据库, 也没用).

另外, 有时候, 一个 infohash 多个 peer, 也不一定在第一个 peer 那里就能成功下载 metadata, 那么就从第二个 peer 那里请求下载, 直到下载成功或者不再有下一个 peer 的时候才会停止.

实现这个的时候 注意内存泄露的问题.

一旦实现了这个, 将会是质的飞跃!

对于BT的原理不是很了解,但是看您的说明,应该可以这样解决:

  1. 对于每个hash创建一个rinfo的队列,并保存最后抓取时间。
  2. 轮询hash列表,如果抓取超时了,就从rinfo队列里取下一个地址,直到队列为空。
  3. 抓取成功了或队列空了就删除该条记录。

我在写了一个队列的实现:https://github.com/sean-liang/p2pspider/blob/master/lib/fetch_queue.js

使用方法:
初始化: 每次抓取超时2000ms,第二个参数是抓取函数
var fetchQueue = new FetchQueue(2000, function(meta) { // fetch data from rinfo } )

收到下载请求时
fetchQueue. push({ infohash: 'e834c096cb8608b9fec9256ec4da8c7aad22d680', rinfo: {address: '192.168.1.1', port: 6881} })

收到数据后调用
fetchQueue.remove(infohash);

Hi, 感谢提供代码. 我认为这个遍历机制不好. 更好的办法是不要遍历; 还有就是, 可以不需要这个多余的超时控制, 本来现目前已经有了这个超时机制, 可以利用目前这个超时的功能, shift 下一个 rinfo; 最后就是, 很多变量名取得不好, 不一致. 比如:

FetchQeueue.prototype.push = function(meta) {
    var hash = meta.infohash;
    if(!this.queues[hash]) {
        this.queues[hash] = { 'lastTriedAt': 0, 'queue': [] };
    } else {
        this.queues[hash].queue.push(meta);
    }
}

meta 应该取 peer, meta是种子文件中的info字段数据.

感谢提供代码!

我认为这个遍历机制不好. 更好的办法是不要遍历; 还有就是, 可以不需要这个多余的超时控制, 本来现目前已经有了这个超时机制, 可以利用目前这个超时的功能, shift 下一个 rinfo

这个方案的原理就是把对同一资源的请求缓存起来。没有看到原来的超时机制,如果有的话,可以在超时的时候从queue里取下一个发起请求,那么遍历就不需要了。

最后就是, 很多变量名取得不好, 不一致

确实对P2P协议不是很了解,只是单纯的考虑解决重复请求的问题。

最后不知道我们说的是不是一个问题,也可能我对您提出的问题理解有误。

我们说的就是同一个地方, 你没理解错误. 这个我自己来做吧.

已搞定. @sean-liang 瞅瞅我的思路如何?

代码看着没有什么问题。但是我merge了你的dev分支,然后跑samples,都没有抓取到任何数据。详见我fork里的merge_with_upstream分支: https://github.com/sean-liang/p2pspider/tree/merge_with_upstream

刚修复了一个 bug, 可能是这个原因. 你现在再试试看.