Results 1 to 16 of 16

Thread: QHttp in thread (QT4)

  1. #1
    Join Date
    Oct 2006
    Posts
    60
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11
    Thanks
    9
    Thanked 3 Times in 3 Posts

    Default QHttp in thread (QT4)

    I am writing a downloading helper application and I have successfully got the program to download a url that is drop into the window. Now I am trying to allow more then one download at a time. Currently if more then one item is dropped in, the other files wait to be downloaded. I believe the fix is to put by QHttp into threads so that each download is its own thread. Does that sound right? If so, how do i do it? I have never worked with threads before.

    Thanks
    mAx

  2. #2
    Join Date
    Jan 2006
    Posts
    128
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Thanked 28 Times in 27 Posts

    Default Re: QHttp in thread (QT4)

    Just a note:
    From my understanding of QHttp it would be sufficient if you just use 1 thread (might even be the main loop) but use multiple QHttp objects.

    QHttp is asynchronous, i.e. it does not block and only works if there is data to be processed, but can only handle one download at the time (it queues the requests internally)

  3. #3
    Join Date
    Oct 2006
    Posts
    60
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11
    Thanks
    9
    Thanked 3 Times in 3 Posts

    Default Re: QHttp in thread (QT4)

    I thought the same thing but how do I have multiple QHttp objects when the user could download as many files as they want? Would my program have to have a hard limit on downloads? Or, is there a way to attach a numeral to a object (QHttp http[0])? Also, if there were multiple QHttps, wouldn't I have to have multiple slots?

    Thanks
    mAx

  4. #4
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts

    Default Re: QHttp in thread (QT4)

    Quote Originally Posted by maxpower View Post
    I thought the same thing but how do I have multiple QHttp objects when the user could download as many files as they want? Would my program have to have a hard limit on downloads? Or, is there a way to attach a numeral to a object (QHttp http[0])? Also, if there were multiple QHttps, wouldn't I have to have multiple slots?
    Each http request returns an unique identifier which can be later used to identify the request.
    J-P Nurmi

  5. #5
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: QHttp in thread (QT4)

    Quote Originally Posted by jpn View Post
    Each http request returns an unique identifier which can be later used to identify the request.
    Yes, but this is only true for a single object. Identifiers will duplicate when multiple QHttp objects are used.

    My suggestion is to use a QList of pointers to QHttp and introduce a sane limit on number of simultaneous downloads.

    Using multiple threads won't help here in any way - you'll still need multiple QHttp objects as QHttp uses the event loop thus it can be handled by a single thread only.

  6. #6
    Join Date
    Oct 2006
    Posts
    60
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11
    Thanks
    9
    Thanked 3 Times in 3 Posts

    Default Re: QHttp in thread (QT4)

    So do you mean like this:

    Qt Code:
    1. QList<QHttp> httpPointers = &http
    To copy to clipboard, switch view to plain text mode 

    What about signals/slots, is it like this:

    Qt Code:
    1. connect(httpPointers.at(0), SIGNAL(something()), this SLOT(somethingelse()));
    To copy to clipboard, switch view to plain text mode 

    ..with a different signal for each pointer? I guess I don't understand how this gives me one QHttp object with a unique set of request ids.

    Thanks
    mAx

  7. #7
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: QHttp in thread (QT4)

    Quote Originally Posted by maxpower View Post
    So do you mean like this:

    Qt Code:
    1. QList<QHttp> httpPointers = &http
    To copy to clipboard, switch view to plain text mode 
    No, I mean like this:
    Qt Code:
    1. QList<QHttp*> httpPointers;
    2. httpPointers << new QHttp(...);
    To copy to clipboard, switch view to plain text mode 

    What about signals/slots, is it like this:

    Qt Code:
    1. connect(httpPointers.at(0), SIGNAL(something()), this SLOT(somethingelse()));
    To copy to clipboard, switch view to plain text mode 
    Yes, but you can connect the signal before adding the http object to the list - so you can use pointers directly, it'll be safer this way

    ..with a different signal for each pointer? I guess I don't understand how this gives me one QHttp object with a unique set of request ids.
    When each signal is emitted, in each slot you can get a pointer to an object emitting the signal by calling QObject::sender(). This way you get instant access to the QHttp object that emitted the signal and you can handle all objects from a single slot this way.

  8. The following user says thank you to wysota for this useful post:

    maxpower (17th February 2007)

  9. #8
    Join Date
    Oct 2006
    Posts
    60
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11
    Thanks
    9
    Thanked 3 Times in 3 Posts

    Default Re: QHttp in thread (QT4)

    Okay, I think I see what I need to do and I will give it a try. But can you explain the signal part again? I understand i only need on slot since from there I can determine which http instance called singaled but how do I add the signals before adding the http object to the list? In your example I am supposed to add a new QHttp object to the list, not an existing one. Or is it like this:

    Qt Code:
    1. QList<QHttp*> httpPointers;
    2. QHttp httpOne = new QHttp();
    3. QHttp httpTwo = new QHttp();
    4. connect(httpOne, SIGNAL(...), this, SLOT(...));
    5. connect(httpTwo, SIGNAL(...), this, SLOT(...));
    6. httpPointers<<httpOne << httpTwo;
    To copy to clipboard, switch view to plain text mode 

    If that is right, are you also saying that I have to create my "sane" about of QHttp ojects statically in the code and then just which one to use based on a counter (and if a previous object is down downloading)?

    Thanks
    mAx

  10. #9
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: QHttp in thread (QT4)

    You can have a queue. If you want to add a download and the list is shorter than X then create a new QHttp object, connect its signals, add it to the list and assign it a request to process (remember to remove it from the list and delete the object when you don't need it anymore so that new objects may be added). If the list already has X objects and you need to perform another download, simply assign the request to one of already existing downloaders (try to do it in a round robin fashion). When the QHttp object finished fetching one request, it'll continue with a next one.

  11. #10
    Join Date
    Oct 2006
    Posts
    60
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11
    Thanks
    9
    Thanked 3 Times in 3 Posts

    Default Re: QHttp in thread (QT4)

    Well, my new code is working and I can download more then one file at a time. I still need to work on the queue part but first I am having a problem removing the QHttp object when the request is finished. Here is my code:

    Qt Code:
    1. void SSDownloaderMWI::httpRequestFinished(int requestId, bool error)
    2. {
    3. QHttp *sendHttp = qobject_cast<QHttp *>(sender());
    4. QList<QTableWidgetItem*> items = downloadsTW->findItems(QString::number(requestId), Qt::MatchFixedString);
    5. if(items.count() != 0)
    6. {
    7. int workingRow = items.at(0)->row();
    8. QFile *file = new QFile();
    9. file->setFileName(downloadsTW->item(workingRow, 10)->text());
    10. file->close();
    11. QTableWidgetItem *finishedStatus = new QTableWidgetItem("completed");
    12. if(error)
    13. {
    14. file->remove();
    15. finishedStatus->setText("Error");
    16. }
    17.  
    18. downloadsTW->setItem(workingRow, 4, finishedStatus);
    19. QTableWidgetItem *requestIdItem = new QTableWidgetItem("");
    20. downloadsTW->setItem(workingRow, 8, requestIdItem);
    21. QMessageBox::information(this,"this",QString::number(httpPointers.count()));
    22. int index = httpPointers.indexOf(sendHttp);
    23. httpPointers.removeAt(index);
    24. QMessageBox::information(this,"this",QString::number(httpPointers.count()));
    25. //delete sendHttp;
    26. }
    27. }
    To copy to clipboard, switch view to plain text mode 

    index is valid as it returns 0 during my tests of only one download running. I get the following error when my program crashes under debug:

    Qt Code:
    1. rogram received signal SIGSEGV, Segmentation fault.
    2. [Switching to Thread -1223771584 (LWP 9087)]
    3. 0xb718ae23 in memmove () from /lib/tls/i686/cmov/libc.so.6
    To copy to clipboard, switch view to plain text mode 

    Any ideas on what I am doing wrong?

    Thanks
    mAx
    Last edited by maxpower; 19th February 2007 at 19:11.

  12. #11
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: QHttp in thread (QT4)

    First of all you can't delete a signal sender from within a slot, you have to call deleteLater(), so that Qt will delete the object after all slots have finished their job.

    Second of all, what the point of this code?
    Qt Code:
    1. QFile *file = new QFile();
    2. file->setFileName(downloadsTW->item(workingRow, 10)->text());
    3. file->close();
    4. QTableWidgetItem *finishedStatus = new QTableWidgetItem("completed");
    5. if(error)
    6. {
    7. file->remove();
    8. finishedStatus->setText("Error");
    9. }
    To copy to clipboard, switch view to plain text mode 
    If you want to delete the file, just call
    Qt Code:
    1. QFile::remove(downloadsTW->item(workingRow, 10)->text());
    To copy to clipboard, switch view to plain text mode 

    Third of all I'd connect to the done() signal and remove the downloader from the queue there instead of in requestFinished.

    As for why the program crashes, could you please display the backtrace (bt) after you get a segfault in the debugger?

  13. The following user says thank you to wysota for this useful post:

    maxpower (19th February 2007)

  14. #12
    Join Date
    Oct 2006
    Posts
    60
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11
    Thanks
    9
    Thanked 3 Times in 3 Posts

    Default Re: QHttp in thread (QT4)

    Well, I thought I needed to close the file properly to ensure my program did not keep it open. Is that not true? I moved the code I had before into a done slot and now I do not see that debug error any more. i will have to keep an eye on it to ensure that it does not return. Based on me no having to manually close the file, here is my new code (just realized though that since I have multiple http objects I can not simply look up the request id in my table to ensure I am working on the correct entry since there could be duplicates, right?):

    Qt Code:
    1. void SSDownloaderMWI::httpRequestFinished(int requestId, bool error)
    2. {
    3. QHttp *http = qobject_cast<QHttp *>(sender());
    4. int currentID = http->currentId();
    5. QList<QTableWidgetItem*> items = downloadsTW->findItems(QString::number(currentID), Qt::MatchFixedString);
    6. if(items.count() != 0)
    7. {
    8. int workingRow = items.at(0)->row();
    9. QTableWidgetItem *finishedStatus = new QTableWidgetItem("completed");
    10. if(error)
    11. {
    12. QFile::remove(downloadsTW->item(workingRow, 10)->text());
    13. finishedStatus->setText("Error");
    14. }
    15.  
    16. downloadsTW->setItem(workingRow, 4, finishedStatus);
    17. QTableWidgetItem *requestIdItem = new QTableWidgetItem("");
    18. downloadsTW->setItem(workingRow, 8, requestIdItem);
    19. }
    20. }
    21.  
    22. void SSDownloaderMWI::httpDone(bool error)
    23. {
    24. QHttp *sendHttp = qobject_cast<QHttp *>(sender());
    25. QMessageBox::information(this,"this",QString::number(httpPointers.count()));
    26. int index = httpPointers.indexOf(sendHttp);
    27. httpPointers.removeAt(index);
    28. QMessageBox::information(this,"this",QString::number(httpPointers.count()));
    29. sendHttp->deleteLater();
    30. }
    To copy to clipboard, switch view to plain text mode 

    Thanks
    mAx

  15. #13
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: QHttp in thread (QT4)

    Quote Originally Posted by maxpower View Post
    Well, I thought I needed to close the file properly to ensure my program did not keep it open. Is that not true?
    It's true (although it's possible that QHttp closes it itself), but here you create a new file object instead of closing the one already open. You should get a pointer to a QIODevice you assigned when making the request and call close on it.

    I moved the code I had before into a done slot and now I do not see that debug error any more. i will have to keep an eye on it to ensure that it does not return.
    It shouldn't unless you start deleting the signalling object from a slot again.

    I can not simply look up the request id in my table to ensure I am working on the correct entry since there could be duplicates, right?):
    Every id is unique per object, so the pair (QHttp*, id) can't duplicate.

    BTW. If you make a qobject_cast, you should check if it doesn't return 0. If you're sure that it is a QHttp* (like in this case), you can make a static_cast instead.

    Qt Code:
    1. int index = httpPointers.indexOf(sendHttp);
    2. httpPointers.removeAt(index);
    To copy to clipboard, switch view to plain text mode 
    I think you can (but don't have to - your code should be slightly faster) substitute it with:
    Qt Code:
    1. httpPointers.removeAll(sendHttp);
    To copy to clipboard, switch view to plain text mode 

  16. The following user says thank you to wysota for this useful post:

    maxpower (19th February 2007)

  17. #14
    Join Date
    Oct 2006
    Posts
    60
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11
    Thanks
    9
    Thanked 3 Times in 3 Posts

    Default Re: QHttp in thread (QT4)

    Okay, thanks for the help AGAIN. I made all the changes you suggested and used QHttp::currentDestinationDevice() to get the pointer to my QFile and close it. I create a new QHttp object each time a new download is added so I will have to find a way to match the calling QHttp object with its entry in the table.

    Thanks again
    mAx
    Last edited by maxpower; 19th February 2007 at 20:20.

  18. #15
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: QHttp in thread (QT4)

    Here is my version of the downloader.
    Attached Files Attached Files

  19. The following 2 users say thank you to wysota for this useful post:

    maxpower (21st February 2007), neuron (23rd January 2009)

  20. #16
    Join Date
    Oct 2006
    Posts
    60
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11
    Thanks
    9
    Thanked 3 Times in 3 Posts

    Default Re: QHttp in thread (QT4)

    Thanks for all your help. I used a QQueue and Download object like the one you used. My program now downloads up to 30 files at a time (user configurable) and stores the file based on a list of suffixes and destinations (user configurable). Now I just got to add more error detection/correction and a Firefox plugin of some sort.

    Thanks
    mAx

Similar Threads

  1. Problem closing a QMainWindow in Qt4.2
    By ian in forum Qt Programming
    Replies: 11
    Last Post: 17th October 2006, 01:49
  2. simple thread layout question
    By mhoover in forum Qt Programming
    Replies: 1
    Last Post: 12th August 2006, 12:02
  3. [QT4] QThread and printing a QList<QPixmap>
    By KShots in forum Qt Programming
    Replies: 3
    Last Post: 24th April 2006, 22:44
  4. Are QHttp n QHttpRequestHeader thread safe?
    By Shambhavi in forum Qt Programming
    Replies: 4
    Last Post: 21st January 2006, 09:33
  5. Replies: 2
    Last Post: 6th January 2006, 22:15

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Qt is a trademark of The Qt Company.