Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Crash in QNetworkManager when used in secondary thread [SOLVED]
Forum Updated to NodeBB v4.3 + New Features

Crash in QNetworkManager when used in secondary thread [SOLVED]

Scheduled Pinned Locked Moved General and Desktop
16 Posts 3 Posters 7.5k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    adnan
    wrote on last edited by
    #1

    I have been working on a download manager. The application uses Qthreads, and QNetworkManager object is created in the run(). The downloads starts but the application crashes in between with the error "The program has unexpectedly finished." The debugger stops at
    "file <unavailable synchronous data>" where file is an QFile object.
    After trying hard to find out the error, i concluded that
    file.write(reply->read(read->bytesAvailable()) causes the application to crash.( reply is an QNetworkReply object)
    if this line is commented every thing works fine, so plz help me out. Below is a part of source code downloadThread.cpp

    @
    #include "downloadthread.h"
    #include "downax.h"
    #include <QMessageBox>
    #include <Qt/qtest.h>

    DownloadThread::DownloadThread(QObject *parent) :
    QThread(parent)
    {

    }

    void DownloadThread::setUrl(QString surl)
    {
    final_url=surl;
    }

    void DownloadThread::run()
    {
    QString args =final_url;
    if (args.isEmpty())
    {
    emit invalidUrl_t();
    return;
    }
    QNetworkProxy proxy;
    QNetworkAccessManager manager1;
    QUrl url = QUrl::fromEncoded(args.toLocal8Bit());
    proxy.setType(QNetworkProxy::HttpProxy);
    proxy.setHostName("172.16.12.2");
    proxy.setPort(3128);
    manager1.setProxy(proxy);

    QNetworkRequest request(url);//request.
    reply=manager1.get(request);
    downloadTime.start();
    connect(&manager1, SIGNAL(finished(QNetworkReply*)),
            SLOT(downloadFinished(QNetworkReply*)));
    connect(reply, SIGNAL(readyRead()),
            SLOT(saveToDisk()));
    connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
            SLOT(showProgress_t(qint64,qint64)));
    QUrl purl = reply->url();
    QString filename = saveFileName(purl);
    file.setFileName(filename);
    if (!file.open(QIODevice::WriteOnly))
    {
       // fprintf(stderr, "Could not open %s for writing: %s\n",
                //qPrintable(filename),
               // qPrintable(file.errorString()));
        //return false;
    }
    
    
    exec&#40;&#41;;
    

    }

    void DownloadThread::showProgress_t(qint64 curr,qint64 total)
    {
    QString unit;
    float curr_r,total_r,curr_s;
    curr_r=curr_s=curr;total_r=total;
    curr_r=curr_r/(10241024);total_r=total/(10241024);
    float speed = curr_s * 1024.0 / downloadTime.elapsed();
    if (speed < 1024) {
    unit = "bytes/sec";
    } else if (speed < 10241024) {
    speed /= 1024;
    unit = "kB/s";
    } else {
    speed /= 1024
    1024;
    unit = "MB/s";
    }
    curr_r = floorf(curr_r * 100 + 0.5) / 100;
    speed = floorf(speed * 100 + 0.5) / 100;

        QString progress=QString::number(curr_r)+" MB  "+QString::number(speed)+" "+unit+"   "+QString::number(total_r)+"MB";
    emit
            downloadProgress_t(progress);
    

    }

    QString DownloadThread::saveFileName(const QUrl &url)
    {

     QString path = url.path();
     QString basename = QFileInfo(path).fileName();
    
     if (basename.isEmpty())
         basename = "download";
    
     if (QFile::exists(basename)) {
         // already exists, don't overwrite
         int i = 0;
         basename += '.';
         while (QFile::exists(basename + QString::number(i)))
             ++i;
    
         basename += QString::number(i);
     }
    
     return basename;
    

    }

    void DownloadThread::saveToDisk()
    {

     qint64 bytes;
     //QByteArray temp;
     bytes=reply->bytesAvailable();
    
     file.write(reply->read(bytes));
    

    }

    void DownloadThread::downloadFinished(QNetworkReply* replyy)
    {
    QString fileUrl;
    QUrl url = reply->url();
    fileUrl=url.toEncoded().constData();
    if (reply->error())
    {
    emit errorDownloading_t(fileUrl,reply->errorString());
    }
    else
    {
    QString filename = saveFileName(url);
    // if (saveToDisk(filename, reply))
    // emit downloadComplete_t(fileUrl,filename);
    file.close();
    }

     //reply->deleteLater();
     this->exit();
    

    }
    @

    [Edit] please use code wrappers

    1 Reply Last reply
    0
    • G Offline
      G Offline
      goetz
      wrote on last edited by
      #2

      First: your QFile object (lacking additional information, I assume it is declared in the class header as attribute) is created in the main thread, as is the QThread subclass itself. You're doing it wrong.™ - see "Threads, Events and QObjects":/wiki/Threads_Events_QObjects wiki article for details.

      Second: why do you use a thread at all? QNetworkAccessManager is asynchronous by default (and uses internal threads from Qt 4.8 on). There is usually no need to put it into a thread of its own.

      Third: simplify the saveToDisk method:

      @
      void DownloadThread::saveToDisk()
      {
      file.write(reply->readAll());
      }
      @

      To analyze further, it would be useful to know at which line the error occurs. Otherwise, a small, complete, compilable example is useful. Leave out everything that is not needed to reproduce the error (e.g. the showProgress_t slot, etc.). Just the class causing the trouble and a main function.

      But please consider seriously dropping your threading, this just adds double asynchronity.

      PS:
      If the error is on file, why do you suspect QNetworkAccessManger to crash, as stated in the thread's title?

      http://www.catb.org/~esr/faqs/smart-questions.html

      1 Reply Last reply
      0
      • A Offline
        A Offline
        adnan
        wrote on last edited by
        #3

        Sir, thank you for replying, actually i am developing a download manager, and to have many simultaneous downloads I opted for threads. Besides, i am going to develop it into a full fledged gui download manager so i think using multithreading is important. If i replace file.write(reply->readAll())
        by QByteArray data=reply->replyAll() with no file object, again the same error occurs. The problem seems to be with QNetworkReply object even in simpler code (multithreaded).
        Besides if i connect finished() signal of networkaccessmanager object to file.write(reply->readAll()), things work fine but behaviour for multiple downloads is wierd. Sometimes the application crashes after two simultaneous downloads or three etc.
        compilable Code:
        http://sharescanner.net84.net/DownAx.tar.gz

        1 Reply Last reply
        0
        • A Offline
          A Offline
          adnan
          wrote on last edited by
          #4

          oh thanks, it worked like a charm, there was no need of using threads

          1 Reply Last reply
          0
          • A Offline
            A Offline
            adnan
            wrote on last edited by
            #5

            Sir, is it possible to create a multi-segment downloader using QNetwork,

            1 Reply Last reply
            0
            • G Offline
              G Offline
              goetz
              wrote on last edited by
              #6

              What's a "multi-segment downloader"?

              http://www.catb.org/~esr/faqs/smart-questions.html

              1 Reply Last reply
              0
              • A Offline
                A Offline
                adnan
                wrote on last edited by
                #7

                Sir, suppose i wish to download a file. so i will simply do:
                QNetworkManager manager.get(request(url))

                Both HTTP and FTP protocols allow the client to specify the start position of the stream. So can QNetworkRequest object be made to generate such a request where we can specify the starting position of the the stream, and if we can, then we can use manager.get(request(url)) multiple times (perhaps upto 6 times as mentioned in qt-doc) to download the the same file at different positions thereby accelerating the download.

                1 Reply Last reply
                0
                • A Offline
                  A Offline
                  andre
                  wrote on last edited by
                  #8

                  Do people still actually use such crappy software such as download "managers" or "accelerators". First of all, I think it is anti-social behaviour to use them to accelerate your downloads. If the server is imposing a limit on the bandwidth to be allocated for a single connection, it does so for a reason. Why do you think you deserve more bandwidth than anyone else?
                  Using them to resume your downloads because you are on an unstable connection is a different discussion.

                  Anyway, AFAIK, this part of the HTTP protocol is not supported by QNAM.

                  1 Reply Last reply
                  0
                  • G Offline
                    G Offline
                    goetz
                    wrote on last edited by
                    #9

                    You can always send your custom headers with the QNetworkRequst. It should be possible to indicate a starting position for a transfer. It's up to you to assemble the different bits and bytes in the correct order to the final file, though.

                    http://www.catb.org/~esr/faqs/smart-questions.html

                    1 Reply Last reply
                    0
                    • A Offline
                      A Offline
                      adnan
                      wrote on last edited by
                      #10

                      Sir, can you plz help me with creating such type of a header. A simple illustrative example would be highly appreciated.

                      1 Reply Last reply
                      0
                      • G Offline
                        G Offline
                        goetz
                        wrote on last edited by
                        #11

                        "QNetworkRequest::setRawHeader() ":/doc/qt-4.8/qnetworkrequest.html#setRawHeader should get you further.

                        http://www.catb.org/~esr/faqs/smart-questions.html

                        1 Reply Last reply
                        0
                        • A Offline
                          A Offline
                          adnan
                          wrote on last edited by
                          #12

                          Thanks Sir, it worked but still a problem.
                          Suppose the file size is 1256498 bytes

                          request.setRawHeader("Range: bytes=0-1256498",""); //downloads the whole file as expected

                          request.setRawHeader("Range: bytes=0-12564",""); //downloads 12565 bytes as expected

                          request.setRawHeader("Range: bytes=5-13339077",""); //downloads 394 bytes for any byte range not starting with zero

                          1 Reply Last reply
                          0
                          • G Offline
                            G Offline
                            goetz
                            wrote on last edited by
                            #13

                            If you do that on the very same url, how should that work?

                            If the file has a size of 1256498, as you state in in the first version "downloads the whole file", then a range of 13339077 clearly exceeds the limits (it's more than 10 times bigger).

                            Did you look at the 394 bytes in the third answer? Could be that it contains an error message?

                            BTW: The correct usage of setRawHeader is:

                            @
                            req.setRawHeader("Range", "bytes=12-155");
                            @

                            http://www.catb.org/~esr/faqs/smart-questions.html

                            1 Reply Last reply
                            0
                            • A Offline
                              A Offline
                              adnan
                              wrote on last edited by
                              #14

                              Sir, actually i had made a mistake in the question in the third case, it was obviously less than the file size.
                              And the problem was with the syntax as you stated and it is now working, even on the same url. Thanks again and thanks again for always replying to my queries.

                              1 Reply Last reply
                              0
                              • A Offline
                                A Offline
                                adnan
                                wrote on last edited by
                                #15

                                My downloader is working fine and i am testing it right now on many sites. Surprisingly it couldn't download any file from furk.net.
                                I tried a simple program using networkaccessmanager it still failed i.e. no problem with my downloader. I tried downloading using other downloaders:
                                fatrat: also developed using qt (it also failed)
                                uget: successfully started download
                                firefox in-built: successful
                                I doubt there is some problem in parsing the url. I am pasting the url but it is expired:
                                http://g9uau0ao42n1kortjknotrql05sr45pbh4uq8s8.gcdn.biz/d/r/Y4APk1wSRw6QCiOdWl1tKD-hKUKyDHCYn5rsDoRf9gPxJkYidwuSQSDO6xBEBEwDZ0ZGZl0iWW384kTVqcNOBw/black Stone V3 - 6.zip

                                there are no spaces at end actually "percent20" which were replaced by spaces by this editor
                                Perhaps such long urls or "percent20" are not supported by qurl/qstring. plz help

                                1 Reply Last reply
                                0
                                • A Offline
                                  A Offline
                                  adnan
                                  wrote on last edited by
                                  #16

                                  Anybody plz reply

                                  1 Reply Last reply
                                  0

                                  • Login

                                  • Login or register to search.
                                  • First post
                                    Last post
                                  0
                                  • Categories
                                  • Recent
                                  • Tags
                                  • Popular
                                  • Users
                                  • Groups
                                  • Search
                                  • Get Qt Extensions
                                  • Unsolved