Как загрузить несколько файлов одновременно с TIdHTTP - PullRequest
0 голосов
/ 28 января 2019

В настоящее время я использую TIdHTTP из Indy с моим Embarcadero C ++ Builder 10.1 Berlin.Я прочитал несколько онлайн-уроков о том, как сделать TIdHTTP многопоточным, но главная проблема в том, что я уже тестировал этот компонент в потоке.

Так вот как он работает.Я создал объект потока и создал функцию для загрузки файла в этом потоке, очевидно, что поток работает нормально, и файл загружается на мой диск.Но когда я создаю дополнительные потоки для загрузки файлов, первый поток останавливается.Я не хочу этого, я хочу, чтобы оба файла продолжали загружаться одновременно (без остановки первого потока), как в IDM (Internet Download Manager).

Класс потока, как в кодениже:

class TIdHTTPThread : public TThread
{
protected:
        void __fastcall Execute();
        void __fastcall PutDownloadedFile();
    public:
        __fastcall TIdHTTPThread(bool CreateSuspended);
        void __fastcall IdHTTPBeginWork(TObject *ASender, TWorkMode AWorkMode,
              __int64 AWorkCountMax);
        void __fastcall IdHTTPWork(TObject *ASender, TWorkMode AWorkMode,
          __int64 AWorkCount);
        void __fastcall IdHTTPEndWork(TObject *ASender, TWorkMode AWorkMode);
        void __fastcall DownloadFile(UnicodeString AFileURL, UnicodeString AFileDest);
        void __fastcall CreateQueue(TWinControl* wcParent, TAlign alAlign);
    private:
        TIdHTTP* IdHTTP;
        TMemoryStream* msMemoryStream;
        UnicodeString uFileURL;
        UnicodeString uFileDest;
        int iDownProgress;
        int iFileSize;
        int iMaxProgress;
        int iDownSpeed;
        TWinControl* wcParent;
        TIFDQueue *ifdQueue;
};

Пожалуйста, не беспокойтесь о дополнительных свойствах и методах в классе, я просто хочу добиться того, что мне нужно в моем вопросе.

Файл CPP:

void __fastcall TIdHTTPThread::CreateQueue(TWinControl* wcParent, TAlign alAlign)
{
    this->wcParent = wcParent;
    ifdQueue = new TIFDQueue(this->wcParent, alAlign);
}

void __fastcall TIdHTTPThread::IdHTTPBeginWork(TObject *ASender, TWorkMode AWorkMode,
              __int64 AWorkCountMax)
{
    this->iFileSize     = AWorkCountMax;
    this->iMaxProgress  = AWorkCountMax;
    ifdQueue->SetFileSize(this->iFileSize);
    ifdQueue->SetMaxProgress(this->iMaxProgress);
    ifdQueue->SetFileURL(this->uFileURL);
    ifdQueue->SetFilePath(this->uFileDest);
    ifdQueue->OnBeginUpdate();
}

void __fastcall TIdHTTPThread::IdHTTPWork(TObject *ASender, TWorkMode AWorkMode,
          __int64 AWorkCount)
{
    this->iDownProgress = AWorkCount;
    this->iDownSpeed    = AWorkCount / 1024;
    ifdQueue->SetDownProgress(this->iDownProgress);
    ifdQueue->SetDownSpeed(this->iDownSpeed);
    ifdQueue->OnWorkUpdate();
}

void __fastcall TIdHTTPThread::IdHTTPEndWork(TObject *ASender, TWorkMode AWorkMode)
{
    ifdQueue->OnEndUpdate();
    this->Terminate();
}
//**//

void __fastcall TIdHTTPThread::DownloadFile(UnicodeString AFileURL, UnicodeString AFileDest)
{
    this->uFileURL  = AFileURL;
    this->uFileDest = AFileDest;
}

void __fastcall TIdHTTPThread::PutDownloadedFile()
{
    try {
        this->msMemoryStream = new TMemoryStream;
        this->IdHTTP                = new TIdHTTP(NULL);
        this->IdHTTP->OnWorkBegin   = this->IdHTTPBeginWork;
        this->IdHTTP->OnWork        = this->IdHTTPWork;
        this->IdHTTP->OnWorkEnd     = this->IdHTTPEndWork;
        this->IdHTTP->ConnectTimeout = 20000;
        this->IdHTTP->ReadTimeout   = 60000;
        this->IdHTTP->Get(this->uFileURL, this->msMemoryStream);
        this->msMemoryStream->SaveToFile(this->uFileDest);
    } __finally {
        delete this->msMemoryStream;
        delete this->IdHTTP;
    }
}

__fastcall TIdHTTPThread::TIdHTTPThread(bool CreateSuspended)
    : TThread(CreateSuspended)
{

}
//---------------------------------------------------------------------------
void __fastcall TIdHTTPThread::Execute()
{
    //---- Place thread code here ----
    FreeOnTerminate = true;
    Synchronize(&this->PutDownloadedFile);
}
//---------------------------------------------------------------------------

ОБНОВЛЕНИЕ:

void __fastcall TIdHTTPThread::PutDownloadedFile()
{
    try {
        this->CookieManager = new TIdCookieManager(NULL);
        this->SSLIOHandlerSocket = new TIdSSLIOHandlerSocketOpenSSL(NULL);
        this->msMemoryStream = new TMemoryStream;
        // Configure SSL IOHandler
        this->SSLIOHandlerSocket->SSLOptions->Method = sslvSSLv23;
        this->SSLIOHandlerSocket->SSLOptions->SSLVersions = TIdSSLVersions() << sslvTLSv1_2 << sslvTLSv1_1 << sslvTLSv1;
        // Setup HTTP
        this->IdHTTP                  = new TIdHTTP(NULL);
        this->ifdQueue->StopDownload(this->IdHTTP);  // Function To stop download When Fired (doesn't fire imidiatly)
        this->IdHTTP->OnWorkBegin     = this->IdHTTPBeginWork;
        this->IdHTTP->OnWork          = this->IdHTTPWork;
        this->IdHTTP->OnWorkEnd       = this->IdHTTPEndWork;
        this->IdHTTP->OnRedirect      = this->IdHTTPRedirect;
        this->IdHTTP->HandleRedirects = true;
        this->IdHTTP->AllowCookies    = true;
        this->IdHTTP->CookieManager   = this->CookieManager;
        this->IdHTTP->IOHandler       = this->SSLIOHandlerSocket;
        this->IdHTTP->Get(this->uFileURL, this->msMemoryStream);
        if ( this->msMemoryStream->Size >= this->IdHTTP->Response->ContentLength ) {
            this->msMemoryStream->SaveToFile(this->uFileName);
        }
    } __finally {
        delete this->msMemoryStream;
        delete this->CookieManager;
        delete this->SSLIOHandlerSocket;
        delete this->IdHTTP;
    }
}

1 Ответ

0 голосов
/ 29 января 2019

Проблема в том, что метод Execute() вашего потока выполняет ВСЕ свою работу внутри вызова Synchronize(), поэтому ВСЕ его работа фактически выполняется внутри основного потока пользовательского интерфейса, что сериализует ваши загрузки и побеждает всю точку.использования рабочего потока.

НЕ вызывайте PutDownloadedFile() сам с Synchronize().Вместо этого вам нужно изменить индивидуальные TIdHTTP статусные события, чтобы использовать Synchronize() (или Queue()) при обновлении элементов управления вашего пользовательского интерфейса.

...