[Qt-interest] Persistent HTTP connections

Mandeep Sandhu mandeepsandhu.chd at gmail.com
Thu Feb 18 11:50:26 CET 2010


On Thu, Feb 18, 2010 at 2:56 PM, Mandeep Sandhu
<mandeepsandhu.chd at gmail.com> wrote:
>>>
>> In theory, it should work like that. Have you tried checking with a network
>> sniffer? If it's not like that, we have a bug (or let's call it performance
>> regression) in Qt.
>
> Thats exactly what I'm trying now...using a sniffer.

I tried using a singleshot timer to start the next download on
receiving the "finished" signal (see attached source). I then used
"NetActViewer" (http://netactview.sourceforge.net/) to view the active
TCP connections to my box (where the webserver is running).

I see that each time a new download starts, the client TCP port number
is changing. This means that a new TCP connection is being made each
time.

I also sniffed one HTTP transaction off the wire...

tshark shows the following for the HTTP request:
...
...
Hypertext Transfer Protocol
    GET /dl.txt HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): GET /dl.txt HTTP/1.1\r\n]
            [Message: GET /dl.txt HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: GET
        Request URI: /dl.txt
        Request Version: HTTP/1.1
    User-Agent: QT 1.0\r\n
    Connection: Keep-Alive\r\n
    Accept-Encoding: gzip\r\n
    Host: 192.168.2.2\r\n
    \r\n
...
...

HTTP response from server:
...
...
Hypertext Transfer Protocol
    HTTP/1.1 200 OK\r\n
        [Expert Info (Chat/Sequence): HTTP/1.1 200 OK\r\n]
            [Message: HTTP/1.1 200 OK\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Version: HTTP/1.1
        Response Code: 200
    Server: nginx/0.7.62\r\n
    Date: Thu, 18 Feb 2010 10:01:21 GMT\r\n
    Content-Type: text/plain\r\n
    Content-Length: 6\r\n
        [Content length: 6]
    Last-Modified: Thu, 18 Feb 2010 08:56:44 GMT\r\n
    Connection: keep-alive\r\n
    Accept-Ranges: bytes\r\n
    \r\n
...
...

So I guess it is using the correct header...but somehow a new
connection is being made each time.

-mandeep


>>
>> To be very sure, I would suggest to not create and send the request from the
>> finished() slot but one event loop spin after that. You can achieve this by
>> using a single shot timer set to 0 msec and sending the request from the
>> timer's slot.
>>
> Thanks for this tip.
>
> Regards,
> -mandeep
>
>>
>> Markus
>>
>
-------------- next part --------------
#include <QDebug>
#include <QApplication>
#include <QFont>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QProgressBar>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTimer>

class DwnLoader : public QWidget
{
    Q_OBJECT

    private:
        QString *url;
        QNetworkAccessManager *netMan;
        QNetworkReply *myReply;
        QProgressBar *pBar;

        int bufSize;
        bool stop;
        int dlCount;

    public:
        DwnLoader(QWidget *parent = 0);

    public slots:
        void download();
        void slotReadyRead();
        void finito();
        void pauseDownload();
        void progress(qint64 bytesReceived, qint64 bytesTotal);
};

DwnLoader::DwnLoader(QWidget *parent) : QWidget(parent)
{
    QPushButton *quit   = new QPushButton("Quit");
    QPushButton *dl     = new QPushButton("Download");
    QPushButton *pause  = new QPushButton("Pause");

    pBar    = new QProgressBar();
    netMan  = new QNetworkAccessManager(this);
    url     = new QString("http://192.168.2.2/largefile.txt");

    bufSize = 128 * 1024;
    dlCount = 0;
    stop = false;

    quit->setFont(QFont("Times", 18, QFont::Bold));
    dl->setFont(QFont("Times", 18, QFont::Bold));

    connect(quit, SIGNAL(clicked()), qApp, SLOT(quit()));
    connect(dl, SIGNAL(clicked()), this, SLOT(download()));
    connect(pause, SIGNAL(clicked()), this, SLOT(pauseDownload()));

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(dl);
    layout->addWidget(pause);
    layout->addWidget(pBar);
    layout->addWidget(quit);

    QWidget *inset = new QWidget(this);
    inset->setGeometry(40,40,150,200);
    inset->setLayout(layout);
}

void DwnLoader::download()
{
    qDebug() << "Starting download from - " << *url;

    QNetworkRequest request;
    request.setUrl(QUrl(*url));
    request.setRawHeader("User-Agent", "QT 1.1");

    myReply = netMan->get(request);
    myReply->setReadBufferSize( bufSize );

    connect(myReply, SIGNAL(finished()),
            this, SLOT(finito()));

    connect(myReply, SIGNAL(readyRead()),
            this, SLOT(slotReadyRead()));

    connect(myReply, SIGNAL(downloadProgress(qint64, qint64)),
            this, SLOT(progress(qint64, qint64)));
}

void DwnLoader::finito()
{
    qDebug() << "Fineeto!";

    qDebug() << "Firing 0 msec timer. Count " << dlCount;
    if (dlCount < 5) {
        dlCount++;
        QTimer::singleShot(0, this, SLOT(download()));
    }

    myReply->deleteLater();
}

void DwnLoader::progress(qint64 bytesReceived, qint64 bytesTotal )
{
    if (stop) {
        return;
    }
    pBar->setMaximum(bytesTotal);
    pBar->setValue(bytesReceived);
}

void DwnLoader::pauseDownload()
{
    if (stop) {
        qDebug() << "Unpausing ...";
    } else {
        qDebug() << "Pausing ...";
    }
    stop = !stop;
    slotReadyRead();
}

void DwnLoader::slotReadyRead()
{
    if (myReply->error() != QNetworkReply::NoError) {
        qDebug() << "ERROR: Error rx'ing my reply";
        return;
    }

    if (stop) {
        qDebug() << "STOPPING read! bytes available" <<
                 myReply->bytesAvailable();
        return;
    }

    if (myReply->bytesAvailable() < bufSize) {
        return;
    }

    QByteArray bytes = myReply->read(bufSize);
    //qDebug() << "Ready read size = " << bytes.size();
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    DwnLoader dwnLoader;
    dwnLoader.show();

    return app.exec();
}

#include "main.moc"


More information about the Qt-interest-old mailing list