Results 1 to 16 of 16

Thread: trying to make QHttp synchronous or threaded

  1. #1
    Join Date
    Apr 2007
    Posts
    46
    Thanks
    4
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default trying to make QHttp synchronous or threaded

    My task is to download a file and then process it right away. Of course it does not work with QHttp's asynchronous API.

    I tried to make QHttp synchronous by calling QHttp::setSocket() and then applying the blocking approach (see Blocking Fortune Client Example), but since requests in QHttp are queued, QHttp::setHost() does not guarantee that the socket has even started connecting, so QAbstractSocket::waitForConnected() does not work.

    Now my second option is to put QHttp in a QThread and then call QThread::wait() -- but I would need a good example for that, having no experience with multi-threaded programming.
    Last edited by ber_44; 8th April 2007 at 09:25.

  2. #2
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: trying to make QHttp synchronous or threaded

    Don't complicate everything with threads.

    QHttp emits the signals requestStarted( int id ) and requestFinished( int id, bool error ).
    With these signals you can synchronize with QHttp.

    Also you can use the state() function and stateChanged() signal.

    For example:

    Qt Code:
    1. CMyClass::CMyClass( QWidget* parent )
    2. :QWidget( parent )
    3. {
    4. mHttp = new QHttp( this );
    5. mSetHostReqID = mHttp->setHost( "www.somesite.org" );
    6.  
    7. connect( mHttp, SIGNAL( requestStarted( int ) ), this, SLOT ( httpStartedRequest( int ) ) );
    8. connect( mHttp, SIGNAL( requestFinished( int, bool ), this, SLOT( httpFinishedRequest ( int, bool ) ) );
    9. connect( mHttp, SIGNAL( stateChanged( int ) ), this, SLOT( httpChangedState( int ) ) );
    10. }
    11.  
    12. void CMyClass::httpStartedRequest( int reqId )
    13. {
    14. if( reqId == mSetHostReqID )
    15. {
    16. // Code for this request goes here
    17. }
    18. else if( reqId == someOtherRequest)
    19. {
    20. //Code for some other request
    21. }
    22. }
    23.  
    24. void CMyClass::httpFinishedRequest( int reqId, bool error )
    25. {
    26. if( reqId == mSetHostReqID )
    27. {
    28. if( error )
    29. // Do something if error occured
    30. else
    31. // Code for this finifhed request goes here
    32. }
    33. else if( reqId == someOtherRequest)
    34. {
    35. if( error )
    36. // Do something if error occured
    37. else
    38. //Code for some other request finished
    39. }
    40. }
    41.  
    42. void CMyClass::httpChangedState( int newState )
    43. {
    44. //Code to do something when this state occurs
    45. switch( newState )
    46. {
    47. case QHttp::Unconnected:
    48. //Code to handle this state
    49. break;
    50. case QHttp::HostLookup:
    51. //Code to handle this state
    52. break;
    53. case QHttp::Connecting:
    54. //Code to handle this state
    55. break;
    56. case QHttp::Sending:
    57. //Code to handle this state
    58. break;
    59. case QHttp::Reading:
    60. //Code to handle this state
    61. break;
    62. case QHttp::Connected:
    63. //Code to handle this state
    64. break;
    65. case QHttp::Cosing:
    66. //Code to handle this state
    67. break;
    68. }
    69. }
    To copy to clipboard, switch view to plain text mode 
    Try it. You shouldn't need a thread at all.

    Regards.
    Last edited by marcel; 8th April 2007 at 11:19. Reason: reformatted to look better

  3. #3
    Join Date
    Apr 2007
    Posts
    46
    Thanks
    4
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: trying to make QHttp synchronous or threaded

    Do you mean this:

    c::c {
    connect(http, SIGNAL(requestFinished(int, bool)),
    this, SLOT(httpRequestFinished(int, bool)));
    // ...
    }

    void c::f() {
    // ...
    reqId[GETNBYTES] = http->get(dir, file);
    // program continues in c::httpRequestFinished()
    }

    void c::httpRequestFinished(int reqId_, bool error) {
    switch (reqId_) {
    case reqId[GETNBYTES]:
    if (error)
    handle_it();
    while (1) {
    // ...
    reqId[i] = http->get(dir, file); // --> I can't imagine these to be not queued
    }
    // ...
    }
    }

    Looks like that requests in a loop are incompatible with this approach.

  4. #4
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: trying to make QHttp synchronous or threaded

    You don't need that while. QHttp is async, therefore the signals.

    You start downloading the first file as you said, then in httpRequestFinished you download the next file, and so on... You always have to wait for the current file to be downloaded, therefore you need to put the files waiting for download in a queue.

  5. #5
    Join Date
    Apr 2007
    Posts
    46
    Thanks
    4
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: trying to make QHttp synchronous or threaded

    Actually, I used while() just to download a number of files. But now I realized that it is not a problem.
    However, now I'm getting a SIGSEGV right at the end of httpRequestFinished().
    I wonder why.

  6. #6
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: trying to make QHttp synchronous or threaded

    Most likely it crashes because of something you do, not because of the signal/slot.
    Could help you if you post some code...

    Regards.

  7. #7
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: trying to make QHttp synchronous or threaded

    What is GETNBYTES ( why do you store requests like this? ) ?
    What does handle_it?

  8. #8
    Join Date
    Apr 2007
    Posts
    46
    Thanks
    4
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: trying to make QHttp synchronous or threaded

    Thanks for offering your help again.
    This is my code that gets SIGSEGV at "case SET_HOST: case SET_USER: break;":
    Qt Code:
    1. #include "httpwindow.h"
    2.  
    3. extern CReadImagesDatabase d;
    4. extern QTimer *timer;
    5.  
    6. HttpWindow::HttpWindow(QWidget *parent, const char * Dir, const char * Dir2, const char *Url, const char *Subdir)
    7. : QWidget(parent) {
    8. /* typical values:
    9. dir (const char *): ....../images_data/
    10. dir2 (const char *): ......./images_data/tmp/
    11. url (QUrl): [url]http://localhost:8000/[/url]
    12. subdir / subdir of images.csv and nbytes.txt on the server / (QString): ./
    13. */
    14.  
    15. our_parent = parent;
    16. dir = Dir;
    17. dir2 = Dir2;
    18. subdir = Subdir;
    19.  
    20. http = new QHttp;
    21. url = new QUrl(QString(Url), QUrl::TolerantMode);
    22. user_abort = false;
    23. httpRequestAborted = false;
    24. reqId.insert(http->setHost(url->host(), url->port() != -1 ? url->port() : 80), SET_HOST);
    25. if (!url->userName().isEmpty())
    26. reqId.insert(http->setUser(url->userName(), url->password()), SET_USER);
    27.  
    28. progressBar = new QProgressBar;
    29. progressBar->setMinimumWidth(progressBar->fontMetrics().width(QLatin1String("X")) * MAX_WIDTH);
    30. statusLabel = new QLabel;
    31. quitButton = new QPushButton(tr("&Quit"));
    32.  
    33. connect(http, SIGNAL(requestFinished(int, bool)),
    34. this, SLOT(httpRequestFinished(int, bool)));
    35. connect(http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)),
    36. this, SLOT(readResponseHeader(const QHttpResponseHeader &)));
    37. connect(quitButton, SIGNAL(clicked()),
    38. this, SLOT(cancelDownload()));
    39.  
    40. QVBoxLayout *mainLayout = new QVBoxLayout;
    41. mainLayout->addWidget(statusLabel);
    42. mainLayout->addWidget(progressBar);
    43. mainLayout->addWidget(quitButton, 0, Qt::AlignRight);
    44. setLayout(mainLayout);
    45.  
    46. setWindowTitle(tr("Updating Isis Images"));
    47.  
    48. }
    49.  
    50. void HttpWindow::updateArchive() {
    51.  
    52. note(0, tr("compare byte count of .csv files"));
    53.  
    54. file = new QFile(dir2 + QString("nbytes.txt"));
    55. if (!file->open(QIODevice::ReadWrite)) {
    56. // no error message, since it is OK to work from a read-only media
    57. delete file; file = 0;
    58. return;
    59. }
    60.  
    61. user_abort = false;
    62. httpRequestAborted = false;
    63. reqId.insert(http->get(url->path() + subdir, file), GET_N_BYTES);
    64. }
    65.  
    66. void HttpWindow::httpRequestFinished(int reqId_, bool error) {
    67. if (user_abort) {
    68. if (file) { file->remove(); delete file; file = 0; }
    69. myQuit();
    70. }
    71.  
    72. qint64 i, tmpi = 0;
    73. bool index_in_tmp;
    74. QList<QString>::iterator j;
    75. QList<QString> new_list;
    76. CReadImagesDatabase e;
    77.  
    78. switch (reqId.value(reqId_)) {
    79.  
    80. case SET_HOST: case SET_USER:
    81. break;
    82. case GET_N_BYTES:
    83. // ...
    84. break;
    85. case GET_NEW_INDEX:
    86. // ...
    87. break;
    88. default: // 0, 1, ... - get fixed image; GET_N_BYTES, etc. are negative values
    89. if (reqId.value(reqId_) >= 0)
    90. // ...
    91. else
    92. // ...
    93. } // end of switch
    94. }
    95.  
    96. void HttpWindow::myQuit() {
    97. // ...
    98. }
    99.  
    100. void HttpWindow::cancelDownload() {
    101. // ...
    102. }
    103.  
    104. void HttpWindow::readResponseHeader(const QHttpResponseHeader &responseHeader) {
    105. // ...
    106. }
    107.  
    108. void HttpWindow::updateDataReadProgress(int bytesRead, int totalBytes) {
    109. // ...
    110. }
    111.  
    112. void HttpWindow::note(QString s, QString t) {
    113. // ...
    114. }
    To copy to clipboard, switch view to plain text mode 
    and the header:
    Qt Code:
    1. #ifndef HTTPWINDOW_H
    2. #define HTTPWINDOW_H
    3.  
    4. #include <QtGui>
    5. #include <QtNetwork>
    6. #include <QtAlgorithms>
    7. #include <stdio.h>
    8. #include <stdlib.h>
    9. #include "ReadImagesDatabase.h"
    10.  
    11. // these consts must not be >= 0
    12. #define SET_HOST -1
    13. #define SET_USER -2
    14. #define GET_N_BYTES -3
    15. #define GET_NEW_INDEX -4
    16.  
    17. #define MAX_WIDTH 30
    18. #define DEBUG
    19.  
    20. class HttpWindow : public QWidget
    21. {
    22. Q_OBJECT
    23. public:
    24. HttpWindow(QWidget *parent, const char *Dir, const char *Dir2, const char *Url, const char *Subdir);
    25. public slots:
    26. void updateArchive();
    27. private slots:
    28. void cancelDownload();
    29. void httpRequestFinished(int requestId, bool error);
    30. void readResponseHeader(const QHttpResponseHeader &responseHeader);
    31. void updateDataReadProgress(int bytesRead, int totalBytes);
    32. private:
    33. void note(QString, QString);
    34. QWidget *our_parent;
    35. bool user_abort;
    36. QString subdir;
    37. void downloadFile(QString);
    38. void myQuit();
    39. QProgressBar *progressBar;
    40. QPushButton *quitButton;
    41. QLabel *statusLabel;
    42. QHttp *http;
    43. QFile *file, *file1;
    44. QUrl *url;
    45. const char *dir, *dir2;
    46. QMap<int, int> reqId;
    47. bool httpRequestAborted;
    48. };
    49.  
    50. #endif
    To copy to clipboard, switch view to plain text mode 
    Last edited by ber_44; 15th April 2007 at 05:49.

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

    Default Re: trying to make QHttp synchronous or threaded

    Is this more or less what you're trying to achieve?

    http://www.qtcentre.org/forum/f-qt-p...-qt4-5695.html

    Especially you might want to take a look at the bundle attached here.

  10. #10
    Join Date
    Apr 2007
    Posts
    46
    Thanks
    4
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: trying to make QHttp synchronous or threaded

    No, wysota, that was a different problem. He wanted to handle multiple requests at the same time, while I want to have one request at a time and in a blocking fashion -- the event loop should wait until the request is finished.
    As I said, QAbstractSocket::waitFor*() functions do not work. marcel suggested me to use QHttp::requestFinished() instead of QThread::wait(), but it currently crashes my program. See the code is my previous post.

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

    Default Re: trying to make QHttp synchronous or threaded

    Did you have a look at the attachment? IMHO it works exactly the same way you want your code to work and it uses requestFinished()

    If you want to force "synchronousness", use a busy loop:

    Qt Code:
    1. while(!someFlagActive) qApp->processEvents();
    To copy to clipboard, switch view to plain text mode 

    And make sure the flag is being set when QHttp finishes its job (in a slot connected to done() or requestFinished()).

    Your code probably segfaults because requestFinished() is emitted after every http "command" - including QHttp::setHost() so probably "reqId.value(reqId_)" returns an invalid value.

  12. #12
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: trying to make QHttp synchronous or threaded

    Look carefully at the QMap you are using.
    It makes no sense crashing in the first to cases where you do nothing...
    Are you sure you don't use those negative error indices somewhere else?

  13. #13
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: trying to make QHttp synchronous or threaded

    Instead of QMap::value( const Key& ), try using QMap::value( const Key&, const &T ).
    This way you'll be able to provide a default (known) value in case the key does not map to any value. You can then use this value to avoid such crashes.

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

    Default Re: trying to make QHttp synchronous or threaded

    How about using QMap::contains() or QMap::find() and checking the iterator for equality with end() (better performance than with contains())?

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

    Default Re: trying to make QHttp synchronous or threaded

    By the way... This:
    Qt Code:
    1. while(!someFlagActive) qApp->processEvents();
    To copy to clipboard, switch view to plain text mode 
    is equivalent to this (just designed worse :P):
    Qt Code:
    1. QHttp *http;
    2. //...
    3. connect(http, SIGNAL(done(bool)), &loop, SLOT(quit())); // you can use a different signal here
    4. loop.exec(QEventLoop::AllEvents|QEventLoop::WaitForMoreEvents);
    5. doSomethingAfterDoneIsEmitted();
    To copy to clipboard, switch view to plain text mode 
    Remember that done() will be processed before the loop exits!

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

    ber_44 (19th April 2007)

  17. #16
    Join Date
    Apr 2007
    Posts
    46
    Thanks
    4
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: trying to make QHttp synchronous or threaded

    > probably "reqId.value(reqId_)" returns an invalid value

    No, I printed it, it's just fine. The crash was caused by something else... Now I'm just getting
    free(): invalid pointer 0x40016ca0!
    after returning from the SET_HOST / SET_USER case (request is queued to happen after HttpWindow::HttpWindow()

    But this does not bother me too much. My program goes on to the first download, BUT when I print file->bytesAvailable() in the GET_N_BYTES case it is zero-size. However, the file does get downloaded just fine, as I see it after the program finishes.

    > If you want to force "synchronousness", use a busy loop
    > QEventLoop loop;
    > connect(http, SIGNAL(done(bool)), &loop, SLOT(quit())); // you can use a different signal here
    > loop.exec(QEventLoop::AllEvents|QEventLoop::WaitFo rMoreEvents);
    > doSomethingAfterDoneIsEmitted();

    That seems to be the solution. IMHO we just replaced the original idea of using QThread::wait() with a local event loop (the program won't execute the next statement until that local event loop has finished).
    Last edited by ber_44; 16th April 2007 at 02:59.

Similar Threads

  1. Window OS make distclean && qmake && make one line
    By patrik08 in forum General Programming
    Replies: 4
    Last Post: 22nd March 2007, 10:43
  2. Compiling with Qmake/Make
    By VireX in forum Newbie
    Replies: 25
    Last Post: 22nd February 2007, 05:57

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
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.