⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 downloader.py

📁 一个多点下载且源码公开的P2P软件
💻 PY
📖 第 1 页 / 共 2 页
字号:
# Written by Bram Cohen# see LICENSE.txt for license informationfrom BitTornado.CurrentRateMeasure import Measurefrom BitTornado.bitfield import Bitfieldfrom random import shufflefrom BitTornado.clock import clocktry:    Trueexcept:    True = 1    False = 0EXPIRE_TIME = 60 * 60class PerIPStats: 	     def __init__(self, ip):        self.numgood = 0        self.bad = {}        self.numconnections = 0        self.lastdownload = None        self.peerid = Noneclass BadDataGuard:    def __init__(self, download):        self.download = download        self.ip = download.ip        self.downloader = download.downloader        self.stats = self.downloader.perip[self.ip]        self.lastindex = None    def failed(self, index, bump = False):        self.stats.bad.setdefault(index, 0)        self.downloader.gotbaddata[self.ip] = 1        self.stats.bad[index] += 1        if len(self.stats.bad) > 1:            if self.download is not None:                self.downloader.try_kick(self.download)            elif self.stats.numconnections == 1 and self.stats.lastdownload is not None:                self.downloader.try_kick(self.stats.lastdownload)        if len(self.stats.bad) >= 3 and len(self.stats.bad) > int(self.stats.numgood/30):            self.downloader.try_ban(self.ip)        elif bump:            self.downloader.picker.bump(index)    def good(self, index):        # lastindex is a hack to only increase numgood by one for each good        # piece, however many chunks come from the connection(s) from this IP        if index != self.lastindex:            self.stats.numgood += 1            self.lastindex = indexclass SingleDownload:    def __init__(self, downloader, connection):        self.downloader = downloader        self.connection = connection        self.choked = True        self.interested = False        self.active_requests = []        self.measure = Measure(downloader.max_rate_period)        self.peermeasure = Measure(downloader.max_rate_period)        self.have = Bitfield(downloader.numpieces)        self.last = -1000        self.last2 = -1000        self.example_interest = None        self.backlog = 2        self.ip = connection.get_ip()        self.guard = BadDataGuard(self)    def _backlog(self, just_unchoked):        self.backlog = min(            2+int(4*self.measure.get_rate()/self.downloader.chunksize),            (2*just_unchoked)+self.downloader.queue_limit() )        if self.backlog > 50:            self.backlog = max(50, self.backlog * 0.075)        return self.backlog        def disconnected(self):        self.downloader.lost_peer(self)        if self.have.complete():            self.downloader.picker.lost_seed()        else:            for i in xrange(len(self.have)):                if self.have[i]:                    self.downloader.picker.lost_have(i)        if self.have.complete() and self.downloader.storage.is_endgame():            self.downloader.add_disconnected_seed(self.connection.get_readable_id())        self._letgo()        self.guard.download = None    def _letgo(self):        if self.downloader.queued_out.has_key(self):            del self.downloader.queued_out[self]        if not self.active_requests:            return        if self.downloader.endgamemode:            self.active_requests = []            return        lost = {}        for index, begin, length in self.active_requests:            self.downloader.storage.request_lost(index, begin, length)            lost[index] = 1        lost = lost.keys()        self.active_requests = []        if self.downloader.paused:            return        ds = [d for d in self.downloader.downloads if not d.choked]        shuffle(ds)        for d in ds:            d._request_more()        for d in self.downloader.downloads:            if d.choked and not d.interested:                for l in lost:                    if d.have[l] and self.downloader.storage.do_I_have_requests(l):                        d.send_interested()                        break    def got_choke(self):        if not self.choked:            self.choked = True            self._letgo()    def got_unchoke(self):        if self.choked:            self.choked = False            if self.interested:                self._request_more(new_unchoke = True)            self.last2 = clock()    def is_choked(self):        return self.choked    def is_interested(self):        return self.interested    def send_interested(self):        if not self.interested:            self.interested = True            self.connection.send_interested()            if not self.choked:                self.last2 = clock()    def send_not_interested(self):        if self.interested:            self.interested = False            self.connection.send_not_interested()    def got_piece(self, index, begin, piece):        length = len(piece)        try:            self.active_requests.remove((index, begin, length))        except ValueError:            self.downloader.discarded += length            return False        if self.downloader.endgamemode:            self.downloader.all_requests.remove((index, begin, length))        self.last = clock()        self.last2 = clock()        self.measure.update_rate(length)        self.downloader.measurefunc(length)        if not self.downloader.storage.piece_came_in(index, begin, piece, self.guard):            self.downloader.piece_flunked(index)            return False        if self.downloader.storage.do_I_have(index):            self.downloader.picker.complete(index)        if self.downloader.endgamemode:            for d in self.downloader.downloads:                if d is not self:                  if d.interested:                    if d.choked:                        assert not d.active_requests                        d.fix_download_endgame()                    else:                        try:                            d.active_requests.remove((index, begin, length))                        except ValueError:                            continue                        d.connection.send_cancel(index, begin, length)                        d.fix_download_endgame()                  else:                      assert not d.active_requests        self._request_more()        self.downloader.check_complete(index)        return self.downloader.storage.do_I_have(index)    def _request_more(self, new_unchoke = False):        assert not self.choked        if self.downloader.endgamemode:            self.fix_download_endgame(new_unchoke)            return        if self.downloader.paused:            return        if len(self.active_requests) >= self._backlog(new_unchoke):            if not (self.active_requests or self.backlog):                self.downloader.queued_out[self] = 1            return        lost_interests = []        while len(self.active_requests) < self.backlog:            interest = self.downloader.picker.next(self.have,                               self.downloader.storage.do_I_have_requests,                               self.downloader.too_many_partials())            if interest is None:                break            self.example_interest = interest            self.send_interested()            loop = True            while len(self.active_requests) < self.backlog and loop:                begin, length = self.downloader.storage.new_request(interest)                self.downloader.picker.requested(interest)                self.active_requests.append((interest, begin, length))                self.connection.send_request(interest, begin, length)                self.downloader.chunk_requested(length)                if not self.downloader.storage.do_I_have_requests(interest):                    loop = False                    lost_interests.append(interest)        if not self.active_requests:            self.send_not_interested()        if lost_interests:            for d in self.downloader.downloads:                if d.active_requests or not d.interested:                    continue                if d.example_interest is not None and self.downloader.storage.do_I_have_requests(d.example_interest):                    continue                for lost in lost_interests:                    if d.have[lost]:                        break                else:                    continue                interest = self.downloader.picker.next(d.have,                                   self.downloader.storage.do_I_have_requests,                                   self.downloader.too_many_partials())                if interest is None:                    d.send_not_interested()                else:                    d.example_interest = interest        if self.downloader.storage.is_endgame():            self.downloader.start_endgame()    def fix_download_endgame(self, new_unchoke = False):        if self.downloader.paused:            return        if len(self.active_requests) >= self._backlog(new_unchoke):            if not (self.active_requests or self.backlog) and not self.choked:                self.downloader.queued_out[self] = 1            return        want = [a for a in self.downloader.all_requests if self.have[a[0]] and a not in self.active_requests]        if not (self.active_requests or want):            self.send_not_interested()            return        if want:            self.send_interested()        if self.choked:            return        shuffle(want)        del want[self.backlog - len(self.active_requests):]        self.active_requests.extend(want)        for piece, begin, length in want:            self.connection.send_request(piece, begin, length)            self.downloader.chunk_requested(length)    def got_have(self, index):        if index == self.downloader.numpieces-1:            self.downloader.totalmeasure.update_rate(self.downloader.storage.total_length-(self.downloader.numpieces-1)*self.downloader.storage.piece_length)            self.peermeasure.update_rate(self.downloader.storage.total_length-(self.downloader.numpieces-1)*self.downloader.storage.piece_length)        else:            self.downloader.totalmeasure.update_rate(self.downloader.storage.piece_length)            self.peermeasure.update_rate(self.downloader.storage.piece_length)        if not self.have[index]:            self.have[index] = True            self.downloader.picker.got_have(index)            if self.have.complete():                self.downloader.picker.became_seed()                if self.downloader.storage.am_I_complete():                    self.downloader.add_disconnected_seed(self.connection.get_readable_id())                    self.connection.close()            elif self.downloader.endgamemode:                self.fix_download_endgame()            elif ( not self.downloader.paused                   and not self.downloader.picker.is_blocked(index)                   and self.downloader.storage.do_I_have_requests(index) ):                if not self.choked:                    self._request_more()                else:                    self.send_interested()        return self.have.complete()    def _check_interests(self):        if self.interested or self.downloader.paused:            return        for i in xrange(len(self.have)):            if ( self.have[i] and not self.downloader.picker.is_blocked(i)                 and ( self.downloader.endgamemode                       or self.downloader.storage.do_I_have_requests(i) ) ):                self.send_interested()                return    def got_have_bitfield(self, have):

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -