防止多个异步请求对同一个 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的原理不是很了解,但是看您的说明,应该可以这样解决:
- 对于每个hash创建一个rinfo的队列,并保存最后抓取时间。
- 轮询hash列表,如果抓取超时了,就从rinfo队列里取下一个地址,直到队列为空。
- 抓取成功了或队列空了就删除该条记录。
我在写了一个队列的实现: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, 可能是这个原因. 你现在再试试看.