1. 程式人生 > >一個簡單的BitTorrent客戶端實現(五):tracker manager和tracker實現

一個簡單的BitTorrent客戶端實現(五):tracker manager和tracker實現

關於tracker和tracker manager

tracker在整個bt協議中起著很重要的作用,從tracker那裡我們可以獲取當前正在下載的peer列表,從而與它們互動,進行檔案的上傳和下載。TrackerManager顧名思義就是管理tracker的。因為可能有多個tracker,所以採用了trackermanager進行管理,所以也顯得比較有條理些。

tracker類的實現

本程式中只實現了TCP tracker,UDP tracker一直苦於沒有找到可供測試的torrent檔案。所以沒實現。tracker類負責與伺服器進行互動,獲取正在下載的peer列表,主要實現在update函式中。

void CTCPTracker::Update()
{

    CURL *pHandle = curl_easy_init();

    m_strTrackerResponse.clear();
    m_nTrackerState = TS_CONNECTING;
    m_nCurrentEvent = GetCurrentEvent();

    string strURL = GenTrackerURL(Event2Str(m_nCurrentEvent));

    curl_easy_setopt(pHandle, CURLOPT_URL, strURL.c_str());
    curl_easy_setopt(pHandle, CURLOPT_WRITEFUNCTION, OnRecvData);
    curl_easy_setopt(pHandle, CURLOPT_WRITEDATA, this
); curl_easy_setopt(pHandle, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(pHandle, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(pHandle, CURLOPT_TIMEOUT, 60); CURLcode nRetCode = curl_easy_perform(pHandle); if (nRetCode == CURLE_OK) { ParseTrackerResponse(); } else { m_nTrackerState = TS_ERROR; m_llNextUpdateTick = GetTickCount() + 15
* 1000; } curl_easy_cleanup(pHandle); }

之前使用純socket程式設計連線tracker伺服器,發行總是連不上,所以改用libcurl,這個東西確實太方便了。用起來太舒服了。關於libcurl,這裡就不作介紹了。

TrackerManager實現

trackermanager主要做了以下兩件重要的事情:
(1)根據種子檔案中的tracker列表建立tracker。

void CTrackerManager::CreateTrackers()
{
    vector<string> vecAnnouce = m_pTorrentTask->GetTorrentFile()->GetAnnounceList();

    vector<string>::iterator it = vecAnnouce.begin();
    for (; it != vecAnnouce.end(); ++it)
    {
        ITracker *pTracker = NULL;
        int nStart = 0;
        int nEnd = 0;
        if (CTorrentParser::FindPattern((*it).c_str(), "HTTP:", nStart, nEnd) == true ||
            CTorrentParser::FindPattern((*it).c_str(), "http:", nStart, nEnd) == true)
        {
            pTracker = new CTCPTracker;
        }
        if (pTracker != NULL)
        {
            pTracker->SetURL((*it).c_str());
            pTracker->SetTrackerManager(this);
            m_vecTrackers.push_back(pTracker);
        }
    }
}

目前這裡只處理了http型別的tracker,採用正則表示式來提取tracker資訊。以後會繼續完善。
(2)在一個執行緒中,讓tracker各自的更新,拉取最新的peer列表。

void CTrackerManager::Svc()
{
    while(!m_bExit)
    {
        vector<ITracker *>::iterator it = m_vecTrackers.begin();
        for (; it != m_vecTrackers.end(); ++it)
        {
            if (m_bExit)
            {
                break;
            }
            if (GetTickCount() < (*it)->GetNextUpdateTick())
            {
                continue;
            }

            (*it)->Update();
        }

        usleep(150000);
    }
}