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

📄 torrentclient.cpp

📁 qt-x11-opensource-src-4.1.4.tar.gz源码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
    }    // Now make up a list of peers where the ones with more points are    // listed many times.    QMultiMap<int, TorrentPeer *>::ConstIterator it = pointMap.constBegin();    while (it != pointMap.constEnd()) {        for (int i = 0; i < it.key() + 1; ++i)            weighedPeers << it.value();        ++it;    }    return weighedPeers;}void TorrentClient::setupIncomingConnection(PeerWireClient *client){    // Connect signals    initializeConnection(client);    // Initialize this client    RateController::instance()->addSocket(client);    d->connections << client;    client->initialize(d->infoHash, d->pieceCount);    client->sendPieceList(d->completedPieces);    emit peerInfoUpdated();    if (d->state == Searching || d->state == Connecting) {        int completed = d->completedPieces.count(true);        if (completed == 0)            d->setState(WarmingUp);        else if (d->incompletePieces.count(true) < 5 && d->pendingPieces.size() > d->incompletePieces.count(true))            d->setState(Endgame);    }    if (d->connections.isEmpty())        scheduleUploads();}void TorrentClient::setupOutgoingConnection(){    PeerWireClient *client = qobject_cast<PeerWireClient *>(sender());    // Update connection statistics.    foreach (TorrentPeer *peer, d->peers) {        if (peer->port == client->peerPort() && peer->address == client->peerAddress()) {            peer->connectTime = peer->lastVisited - peer->connectStart;            break;        }    }    // Send handshake and piece list    client->initialize(d->infoHash, d->pieceCount);    client->sendPieceList(d->completedPieces);    emit peerInfoUpdated();    if (d->state == Searching || d->state == Connecting) {        int completed = d->completedPieces.count(true);        if (completed == 0)            d->setState(WarmingUp);        else if (d->incompletePieces.count(true) < 5 && d->pendingPieces.size() > d->incompletePieces.count(true))            d->setState(Endgame);    }}void TorrentClient::initializeConnection(PeerWireClient *client){    connect(client, SIGNAL(connected()),            this, SLOT(setupOutgoingConnection()));    connect(client, SIGNAL(disconnected()),            this, SLOT(removeClient()));    connect(client, SIGNAL(error(QAbstractSocket::SocketError)),            this, SLOT(removeClient()));    connect(client, SIGNAL(piecesAvailable(const QBitArray &)),            this, SLOT(peerPiecesAvailable(const QBitArray &)));    connect(client, SIGNAL(blockRequested(int, int, int)),            this, SLOT(peerRequestsBlock(int, int, int)));    connect(client, SIGNAL(blockReceived(int, int, const QByteArray &)),            this, SLOT(blockReceived(int, int, const QByteArray &)));    connect(client, SIGNAL(choked()),            this, SLOT(peerChoked()));    connect(client, SIGNAL(unchoked()),            this, SLOT(peerUnchoked()));    connect(client, SIGNAL(bytesWritten(qint64)),            this, SLOT(peerWireBytesWritten(qint64)));    connect(client, SIGNAL(bytesReceived(qint64)),            this, SLOT(peerWireBytesReceived(qint64)));}void TorrentClient::removeClient(){    PeerWireClient *client = static_cast<PeerWireClient *>(sender());    // Remove the host from our list of known peers if the connection    // failed.    if (client->peer() && client->error() == QAbstractSocket::ConnectionRefusedError)        d->peers.removeAll(client->peer());    // Remove the client from RateController and all structures.    RateController::instance()->removeSocket(client);    d->connections.removeAll(client);    QMultiMap<PeerWireClient *, TorrentPiece *>::Iterator it = d->payloads.find(client);    while (it != d->payloads.end() && it.key() == client) {        TorrentPiece *piece = it.value();        piece->inProgress = false;        piece->requestedBlocks.fill(false);        it = d->payloads.erase(it);    }    // Remove pending read requests.    QMapIterator<int, PeerWireClient *> it2(d->readIds);    while (it2.findNext(client))        d->readIds.remove(it2.key());    // Delete the client later.    disconnect(client, SIGNAL(disconnected()), this, SLOT(removeClient()));    client->deleteLater();    ConnectionManager::instance()->removeConnection(client);    emit peerInfoUpdated();    d->callPeerConnector();}void TorrentClient::peerPiecesAvailable(const QBitArray &pieces){    PeerWireClient *client = qobject_cast<PeerWireClient *>(sender());    // Find the peer in our list of announced peers. If it's there,    // then we can use the piece list into to gather statistics that    // help us decide what peers to connect to.    TorrentPeer *peer = 0;    QList<TorrentPeer *>::Iterator it = d->peers.begin();    while (it != d->peers.end()) {        if ((*it)->address == client->peerAddress() && (*it)->port == client->peerPort()) {            peer = *it;            break;        }        ++it;    }    // If the peer is a seed, and we are in seeding mode, then the    // peer is uninteresting.    if (pieces.count(true) == d->pieceCount) {        if (peer)            peer->seed = true;        emit peerInfoUpdated();        if (d->state == Seeding) {            client->abort();            return;        } else {            if (peer)                peer->interesting = true;            if ((client->peerWireState() & PeerWireClient::InterestedInPeer) == 0)                client->sendInterested();            d->callScheduler();            return;        }    }    // Update our list of available pieces.    if (peer) {        peer->pieces = pieces;        peer->numCompletedPieces = pieces.count(true);    }    // Check for interesting pieces, and tell the peer whether we are    // interested or not.    bool interested = false;    int piecesSize = pieces.size();    for (int pieceIndex = 0; pieceIndex < piecesSize; ++pieceIndex) {        if (!pieces.testBit(pieceIndex))            continue;        if (!d->completedPieces.testBit(pieceIndex)) {            interested = true;            if ((client->peerWireState() & PeerWireClient::InterestedInPeer) == 0) {                if (peer)                    peer->interesting = true;                client->sendInterested();            }            QMultiMap<PeerWireClient *, TorrentPiece *>::Iterator it = d->payloads.find(client);            int inProgress = 0;            while (it != d->payloads.end() && it.key() == client) {                if (it.value()->inProgress)                    inProgress += it.value()->requestedBlocks.count(true);                ++it;            }            if (!inProgress)                d->callScheduler();            break;        }    }    if (!interested && (client->peerWireState() & PeerWireClient::InterestedInPeer)) {        if (peer)            peer->interesting = false;        client->sendNotInterested();    }}void TorrentClient::peerRequestsBlock(int pieceIndex, int begin, int length){    PeerWireClient *client = qobject_cast<PeerWireClient *>(sender());    // Silently ignore requests from choked peers    if (client->peerWireState() & PeerWireClient::ChokingPeer)        return;    // Silently ignore requests for pieces we don't have.    if (!d->completedPieces.testBit(pieceIndex))        return;    // Request the block from the file manager    d->readIds.insert(d->fileManager.read(pieceIndex, begin, length),                      qobject_cast<PeerWireClient *>(sender()));}void TorrentClient::blockReceived(int pieceIndex, int begin, const QByteArray &data){    PeerWireClient *client = qobject_cast<PeerWireClient *>(sender());    if (data.size() == 0) {        client->abort();        return;    }    // Ignore it if we already have this block.    int blockBit = begin / BlockSize;    TorrentPiece *piece = d->pendingPieces.value(pieceIndex);    if (!piece || piece->completedBlocks.testBit(blockBit)) {        // Discard blocks that we already have, and fill up the pipeline.        requestMore(client);        return;    }    // If we are in warmup or endgame mode, cancel all duplicate    // requests for this block.    if (d->state == WarmingUp || d->state == Endgame) {        QMultiMap<PeerWireClient *, TorrentPiece *>::Iterator it = d->payloads.begin();        while (it != d->payloads.end()) {            PeerWireClient *otherClient = it.key();            if (otherClient != client && it.value()->index == pieceIndex) {                if (otherClient->incomingBlocks().contains(TorrentBlock(pieceIndex, begin, data.size())))                    it.key()->cancelRequest(pieceIndex, begin, data.size());            }            ++it;        }    }    if (d->state != Downloading && d->state != Endgame && d->completedPieces.count(true) > 0)        d->setState(Downloading);    // Store this block    d->fileManager.write(pieceIndex, begin, data);    piece->completedBlocks.setBit(blockBit);    piece->requestedBlocks.clearBit(blockBit);    if (blocksLeftForPiece(piece) == 0) {        // Ask the file manager to verify the newly downloaded piece        d->fileManager.verifyPiece(piece->index);                // Remove this piece from all payloads        QMultiMap<PeerWireClient *, TorrentPiece *>::Iterator it = d->payloads.begin();        while (it != d->payloads.end()) {            if (!it.value() || it.value()->index == piece->index)                it = d->payloads.erase(it);            else                ++it;        }    }    // Fill up the pipeline.    requestMore(client);}void TorrentClient::peerWireBytesWritten(qint64 size){    if (!d->transferRateTimer)        d->transferRateTimer = startTimer(RateControlTimerDelay);    d->uploadRate[0] += size;    d->uploadedBytes += size;    emit dataSent(size);}void TorrentClient::peerWireBytesReceived(qint64 size){    if (!d->transferRateTimer)        d->transferRateTimer = startTimer(RateControlTimerDelay);    d->downloadRate[0] += size;    d->downloadedBytes += size;    emit dataSent(size);}int TorrentClient::blocksLeftForPiece(const TorrentPiece *piece) const{    int blocksLeft = 0;    int completedBlocksSize = piece->completedBlocks.size();    for (int i = 0; i < completedBlocksSize; ++i) {        if (!piece->completedBlocks.testBit(i))            ++blocksLeft;    }    return blocksLeft;}void TorrentClient::scheduleUploads(){    // Generate a list of clients sorted by their transfer    // speeds.  When leeching, we sort by download speed, and when    // seeding, we sort by upload speed. Seeds are left out; there's    // no use in unchoking them.    QList<PeerWireClient *> allClients = d->connections;    QMultiMap<int, PeerWireClient *> transferSpeeds;    foreach (PeerWireClient *client, allClients) {        if (client->state() == QAbstractSocket::ConnectedState            && client->availablePieces().count(true) != d->pieceCount) {            if (d->state == Seeding) {                transferSpeeds.insert(client->uploadSpeed(), client);            } else {                transferSpeeds.insert(client->downloadSpeed(), client);            }        }    }    // Unchoke the top 'MaxUploads' downloaders (peers that we are    // uploading to) and choke all others.    int maxUploaders = MaxUploads;    QMapIterator<int, PeerWireClient *> it(transferSpeeds);    it.toBack();    while (it.hasPrevious()) {        PeerWireClient *client = it.previous().value();        bool interested = (client->peerWireState() & PeerWireClient::PeerIsInterested);        if (maxUploaders) {            allClients.removeAll(client);            if (client->peerWireState() & PeerWireClient::ChokingPeer)                client->unchokePeer();            --maxUploaders;            continue;        }        if ((client->peerWireState() & PeerWireClient::ChokingPeer) == 0) {            if ((rand() % 10) == 0)                 client->abort();            else                client->chokePeer();            allClients.removeAll(client);        }        if (!interested)            allClients.removeAll(client);    }    // Only interested peers are left in allClients. Unchoke one    // random peer to allow it to compete for a position among the    // downloaders.  (This is known as an "optimistic unchoke".)    if (!allClients.isEmpty()) {        PeerWireClient *client = allClients[rand() % allClients.size()];        if (client->peerWireState() & PeerWireClient::ChokingPeer)            client->unchokePeer();    }}void TorrentClient::scheduleDownloads(){    d->schedulerCalled = false;    if (d->state == Stopping || d->state == Paused || d->state == Idle)        return;    // Check what each client is doing, and assign payloads to those    // who are either idle or done.    foreach (PeerWireClient *client, d->connections)        schedulePieceForClient(client);}void TorrentClient::schedulePieceForClient(PeerWireClient *client){    // Only schedule connected clients.    if (client->state() != QTcpSocket::ConnectedState)        return;    // The peer has choked us; try again later.

⌨️ 快捷键说明

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