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

📄 torrentclient.cpp

📁 qt-x11-opensource-src-4.1.4.tar.gz源码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
    if (client->peerWireState() & PeerWireClient::ChokedByPeer)        return;    // Make a list of all the client's pending pieces, and count how    // many blocks have been requested.    QList<int> currentPieces;    bool somePiecesAreNotInProgress = false;    TorrentPiece *lastPendingPiece = 0;    QMultiMap<PeerWireClient *, TorrentPiece *>::Iterator it = d->payloads.find(client);    while (it != d->payloads.end() && it.key() == client) {        lastPendingPiece = it.value();        if (lastPendingPiece->inProgress) {            currentPieces << lastPendingPiece->index;        } else {            somePiecesAreNotInProgress = true;        }        ++it;    }    // Skip clients that already have too many blocks in progress.    if (client->incomingBlocks().size() >= ((d->state == Endgame || d->state == WarmingUp)                                            ? MaxBlocksInMultiMode : MaxBlocksInProgress))        return;    // If all pieces are in progress, but we haven't filled up our    // block requesting quota, then we need to schedule another piece.    if (!somePiecesAreNotInProgress || client->incomingBlocks().size() > 0)        lastPendingPiece = 0;    TorrentPiece *piece = lastPendingPiece;    // In warmup state, all clients request blocks from the same pieces.    if (d->state == WarmingUp && d->pendingPieces.size() >= 4) {        piece = d->payloads.value(client);        if (!piece) {            QList<TorrentPiece *> values = d->pendingPieces.values();            piece = values.value(rand() % values.size());            piece->inProgress = true;            d->payloads.insert(client, piece);        }        if (piece->completedBlocks.count(false) == client->incomingBlocks().size())            return;    }    // If no pieces are currently in progress, schedule a new one.    if (!piece) {        // Build up a list of what pieces that we have not completed        // are available to this client.        QBitArray incompletePiecesAvailableToClient = d->incompletePieces;        // Remove all pieces that are marked as being in progress        // already (i.e., pieces that this or other clients are        // already waiting for). A special rule applies to warmup and        // endgame mode; there, we allow several clients to request        // the same piece. In endgame mode, this only applies to        // clients that are currently uploading (more than 1.0KB/s).        if ((d->state == Endgame && client->uploadSpeed() < 1024) || d->state != WarmingUp) {            QMap<int, TorrentPiece *>::ConstIterator it = d->pendingPieces.constBegin();            while (it != d->pendingPieces.constEnd()) {                if (it.value()->inProgress)                    incompletePiecesAvailableToClient.clearBit(it.key());                ++it;            }        }        // Remove all pieces that the client cannot download.        incompletePiecesAvailableToClient &= client->availablePieces();        // Remove all pieces that this client has already requested.        foreach (int i, currentPieces)            incompletePiecesAvailableToClient.clearBit(i);        // Only continue if more pieces can be scheduled. If no pieces        // are available and no blocks are in progress, just leave        // the connection idle; it might become interesting later.        if (incompletePiecesAvailableToClient.count(true) == 0)            return;        // Check if any of the partially completed pieces can be        // recovered, and if so, pick a random one of them.        QList<TorrentPiece *> partialPieces;        QMap<int, TorrentPiece *>::ConstIterator it = d->pendingPieces.constBegin();        while (it != d->pendingPieces.constEnd()) {            TorrentPiece *tmp = it.value();            if (incompletePiecesAvailableToClient.testBit(it.key())) {                if (!tmp->inProgress || d->state == WarmingUp || d->state == Endgame) {                    partialPieces << tmp;                    break;                }            }            ++it;        }        if (!partialPieces.isEmpty())            piece = partialPieces.value(rand() % partialPieces.size());        if (!piece) {            // Pick a random piece 3 out of 4 times; otherwise, pick either            // one of the most common or the least common pieces available,            // depending on the state we're in.            int pieceIndex = 0;            if (d->state == WarmingUp || (rand() & 4) == 0) {                int *occurrances = new int[d->pieceCount];                memset(occurrances, 0, d->pieceCount * sizeof(int));                                // Count how many of each piece are available.                foreach (PeerWireClient *peer, d->connections) {                    QBitArray peerPieces = peer->availablePieces();                    int peerPiecesSize = peerPieces.size();                    for (int i = 0; i < peerPiecesSize; ++i) {                        if (peerPieces.testBit(i))                            ++occurrances[i];                    }                }                // Find the rarest or most common pieces.                int numOccurrances = d->state == WarmingUp ? 0 : 99999;                QList<int> piecesReadyForDownload;                for (int i = 0; i < d->pieceCount; ++i) {                    if (d->state == WarmingUp) {                        // Add common pieces                        if (occurrances[i] >= numOccurrances                            && incompletePiecesAvailableToClient.testBit(i)) {                            if (occurrances[i] > numOccurrances)                                piecesReadyForDownload.clear();                            piecesReadyForDownload.append(i);                            numOccurrances = occurrances[i];                        }                    } else {                        // Add rare pieces                        if (occurrances[i] <= numOccurrances                            && incompletePiecesAvailableToClient.testBit(i)) {                            if (occurrances[i] < numOccurrances)                                piecesReadyForDownload.clear();                            piecesReadyForDownload.append(i);                            numOccurrances = occurrances[i];                        }                    }                }                // Select one piece randomly                pieceIndex = piecesReadyForDownload.at(rand() % piecesReadyForDownload.size());                delete [] occurrances;            } else {                // Make up a list of available piece indices, and pick                // a random one.                QList<int> values;                int incompletePiecesAvailableToClientSize = incompletePiecesAvailableToClient.size();                for (int i = 0; i < incompletePiecesAvailableToClientSize; ++i) {                    if (incompletePiecesAvailableToClient.testBit(i))                        values << i;                }                pieceIndex = values.at(rand() % values.size());            }            // Create a new TorrentPiece and fill in all initial            // properties.            piece = new TorrentPiece;            piece->index = pieceIndex;            piece->length = d->fileManager.pieceLengthAt(pieceIndex);            int numBlocks = piece->length / BlockSize;            if (piece->length % BlockSize)                ++numBlocks;            piece->completedBlocks.resize(numBlocks);            piece->requestedBlocks.resize(numBlocks);            d->pendingPieces.insert(pieceIndex, piece);        }        piece->inProgress = true;        d->payloads.insert(client, piece);    }    // Request more blocks from all pending pieces.    requestMore(client);}void TorrentClient::requestMore(PeerWireClient *client){    // Make a list of all pieces this client is currently waiting for,    // and count the number of blocks in progress.    QMultiMap<PeerWireClient *, TorrentPiece *>::Iterator it = d->payloads.find(client);    int numBlocksInProgress = client->incomingBlocks().size();    QList<TorrentPiece *> piecesInProgress;    while (it != d->payloads.end() && it.key() == client) {        TorrentPiece *piece = it.value();        if (piece->inProgress || (d->state == WarmingUp || d->state == Endgame))            piecesInProgress << piece;        ++it;    }    // If no pieces are in progress, call the scheduler.    if (piecesInProgress.isEmpty() && d->incompletePieces.count(true)) {        d->callScheduler();        return;    }    // If too many pieces are in progress, there's nothing to do.    int maxInProgress = ((d->state == Endgame || d->state == WarmingUp)                         ? MaxBlocksInMultiMode : MaxBlocksInProgress);    if (numBlocksInProgress == maxInProgress)        return;        // Starting with the first piece that we're waiting for, request    // blocks until the quota is filled up.    foreach (TorrentPiece *piece, piecesInProgress) {        numBlocksInProgress += requestBlocks(client, piece, maxInProgress - numBlocksInProgress);        if (numBlocksInProgress == maxInProgress)            break;    }    // If we still didn't fill up the quota, we need to schedule more    // pieces.    if (numBlocksInProgress < maxInProgress && d->state != WarmingUp)        d->callScheduler();}int TorrentClient::requestBlocks(PeerWireClient *client, TorrentPiece *piece, int maxBlocks){    // Generate the list of incomplete blocks for this piece.    QVector<int> bits;    int completedBlocksSize = piece->completedBlocks.size();    for (int i = 0; i < completedBlocksSize; ++i) {        if (!piece->completedBlocks.testBit(i) && !piece->requestedBlocks.testBit(i))            bits << i;    }    // Nothing more to request.    if (bits.size() == 0) {        if (d->state != WarmingUp && d->state != Endgame)            return 0;        bits.clear();        for (int i = 0; i < completedBlocksSize; ++i) {            if (!piece->completedBlocks.testBit(i))                bits << i;        }    }    if (d->state == WarmingUp || d->state == Endgame) {        // By randomizing the list of blocks to request, we        // significantly speed up the warmup and endgame modes, where        // the same blocks are requested from multiple peers. The        // speedup comes from an increased chance of receiving        // different blocks from the different peers.        for (int i = 0; i < bits.size(); ++i) {            int a = rand() % bits.size();            int b = rand() % bits.size();            int tmp = bits[a];            bits[a] = bits[b];            bits[b] = tmp;        }    }    // Request no more blocks than we've been asked to.    int blocksToRequest = qMin(maxBlocks, bits.size());    // Calculate the offset and size of each block, and send requests.    for (int i = 0; i < blocksToRequest; ++i) {        int blockSize = BlockSize;        if ((piece->length % BlockSize) && bits.at(i) == completedBlocksSize - 1)            blockSize = piece->length % BlockSize;        client->requestBlock(piece->index, bits.at(i) * BlockSize, blockSize);        piece->requestedBlocks.setBit(bits.at(i));    }    return blocksToRequest;}void TorrentClient::peerChoked(){    PeerWireClient *client = qobject_cast<PeerWireClient *>(sender());    if (!client)        return;    // When the peer chokes us, we immediately forget about all blocks    // we've requested from it. We also remove the piece from out    // payload, making it available to other clients.    QMultiMap<PeerWireClient *, TorrentPiece *>::Iterator it = d->payloads.find(client);    while (it != d->payloads.end() && it.key() == client) {        it.value()->inProgress = false;        it.value()->requestedBlocks.fill(false);        it = d->payloads.erase(it);    }}void TorrentClient::peerUnchoked(){    PeerWireClient *client = qobject_cast<PeerWireClient *>(sender());    if (!client)        return;    // We got unchoked, which means we can request more blocks.    if (d->state != Seeding)        d->callScheduler();}void TorrentClient::addToPeerList(const QList<TorrentPeer> &peerList){    // Add peers we don't already know of to our list of peers.    foreach (TorrentPeer peer, peerList) {        if (peer.address == TorrentServer::instance()->serverAddress()            && peer.port == TorrentServer::instance()->serverPort())            continue;        bool known = false;        foreach (TorrentPeer *knownPeer, d->peers) {            if (knownPeer->port == peer.port                && knownPeer->address == peer.address) {                known = true;                break;            }        }        if (!known) {            TorrentPeer *newPeer = new TorrentPeer;            *newPeer = peer;            newPeer->interesting = true;            newPeer->seed = false;            newPeer->lastVisited = 0;            newPeer->connectStart = 0;            newPeer->connectTime = 999999;            newPeer->pieces.resize(d->pieceCount);            newPeer->numCompletedPieces = 0;            d->peers << newPeer;        }    }    // If we've got more peers than we can connect to, we remove some    // of the peers that have no (or low) activity.    int maxPeers = ConnectionManager::instance()->maxConnections() * 3;    if (d->peers.size() > maxPeers) {        // Find what peers are currently connected & active        QSet<TorrentPeer *> activePeers;        foreach (TorrentPeer *peer, d->peers) {            foreach (PeerWireClient *client, d->connections) {                if (client->peer() == peer && (client->downloadSpeed() + client->uploadSpeed()) > 1024)                    activePeers << peer;            }        }        // Remove inactive peers from the peer list until we're below        // the max connections count.        QList<int> toRemove;        for (int i = 0; i < d->peers.size() && (d->peers.size() - toRemove.size()) > maxPeers; ++i) {            if (!activePeers.contains(d->peers.at(i)))                toRemove << i;        }        QListIterator<int> toRemoveIterator(toRemove);        toRemoveIterator.toBack();        while (toRemoveIterator.hasPrevious())            d->peers.removeAt(toRemoveIterator.previous());        // If we still have too many peers, remove the oldest ones.        while (d->peers.size() > maxPeers)            d->peers.takeFirst();    }    if (d->state != Paused && d->state != Stopping && d->state != Idle) {        if (d->state == Searching || d->state == WarmingUp)            connectToPeers();        else            d->callPeerConnector();    }}void TorrentClient::trackerStopped(){    d->setState(Idle);    emit stopped();}void TorrentClient::updateProgress(int progress){    if (progress == -1 && d->pieceCount > 0) {        int newProgress = (d->completedPieces.count(true) * 100) / d->pieceCount;        if (d->lastProgressValue != newProgress) {            d->lastProgressValue = newProgress;            emit progressUpdated(newProgress);        }    } else if (d->lastProgressValue != progress) {        d->lastProgressValue = progress;        emit progressUpdated(progress);    }}

⌨️ 快捷键说明

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