Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 4

Qt-interest Archive, June 2007
How to handle concurrent requests with QTcpServer


Message 1 in thread

Hello to everybody on the list.

I am writing HTTP server for my needs using QT4, and while doing some 
testing and benchmarking
using Apache's ab, i found that my server cannot handle concurrent requests.

When concurrency is 1, everything is great, and it works 20% faster than 
apache.
When i set concurrency to > 1, i get the following error:
apr_recv: An existing connection was forcibly closed by the remote host. 
(730054)

So my question is how does one handle concurrent requests with QTcpServer?

Thanks,
Yuriy



--
 [ signature omitted ] 

Message 2 in thread

Hi,

> I am writing HTTP server for my needs using QT4, and while doing some 
> testing and benchmarking
> using Apache's ab, i found that my server cannot handle concurrent requests.
> 
> When concurrency is 1, everything is great, and it works 20% faster than 
> apache.
> When i set concurrency to > 1, i get the following error:
> apr_recv: An existing connection was forcibly closed by the remote host. 
> (730054)

I understand you set concurrency in Apache's "ab" benchmarking tool using the 
"-c" option, and that message you're showing us is emitted by "ab".

> So my question is how does one handle concurrent requests with QTcpServer?

Examples are provided with Qt and the documentation explains how to use the 
QTcpServer class:
	http://doc.trolltech.com/4.3/qtcpserver.html
Try modifying one of the examples to fit your needs. Doesn't it work for you?

--
 [ signature omitted ] 

Message 3 in thread

Dimitri wrote:
 > Hi,
 >
 >> I am writing HTTP server for my needs using QT4, and while doing 
some testing and benchmarking
 >> using Apache's ab, i found that my server cannot handle concurrent 
requests.
 >>
 >> When concurrency is 1, everything is great, and it works 20% faster 
than apache.
 >> When i set concurrency to > 1, i get the following error:
 >> apr_recv: An existing connection was forcibly closed by the remote 
host. (730054)
 >
 > I understand you set concurrency in Apache's "ab" benchmarking tool 
using the "-c" option, and that message you're showing us is emitted by 
"ab".
 >

Yes, by ab. Looks like server socket cannot accept two connections if 
those are concurrent.

 >> So my question is how does one handle concurrent requests with 
QTcpServer?
 >
 > Examples are provided with Qt and the documentation explains how to 
use the QTcpServer class:
 >     http://doc.trolltech.com/4.3/qtcpserver.html
 > Try modifying one of the examples to fit your needs. Doesn't it work 
for you?

That's what i do, everything as described. On newConnection() i get 
nextPendingConnection() and work with socket. and with browser, and 
ab/concurrency set to 1 everything is fine.

But QTcpServer design is event driven, which means as i understand that 
every signal/slot is called by event loop, sequentially, one after another.

And here i don't quite understand how to work with concurrent requests.
I was thinking about putting all procession in threads, but i am not 
sure if this would help.  Even if i serve 10 bytes page it still fails.

Maybe it is not going to cause any troubles in production, but i still 
wanted to clear this out, if it is my fault, or maybe this is just the 
way it works.

If someone with deep knowledge of how it works could give me a pointer, 
i would really appreciate it.

Thanks,
Yuriy

P.S. Here is the simplified server's source code

QHttpServer::QHttpServer( int p, QObject* parent )
: QTcpServer(parent),
       port(p)
{
    connect( this, SIGNAL( newConnection() ), this, 
SLOT(onNewConnection() ) );
}

bool QHttpServer::start()
{
     if( !listen(QHostAddress::Any, port) )
     {
         qDebug() << "Could not start server: " << errorString();
         return false;
     }
     return true;
}

void QHttpServer::onNewConnection()
{
     QTcpSocket *clientConnection = nextPendingConnection();
     connect(clientConnection, SIGNAL(disconnected()),
             this, SLOT( connectionClosed() ));

     connect( clientConnection, SIGNAL( readyRead() ), this, SLOT( 
onDataRecieve() ) );

     mCurrentSocket = clientConnection;
     disconnected = false;
}

void QHttpServer::connectionClosed()
{
     mCurrentSocket->deleteLater();
     disconnected = true;
}

void QHttpServer::onDataRecieve()
{

     if(disconnected)
     {
         return;
     }

     ///////////
         .........
     read/write from/to socket

     //////////

         mCurrentSocket->disconnectFromHost();
}

void QHttpServer::discardClient()
{
     mCurrentSocket->disconnectFromHost();
}


--
 [ signature omitted ] 

Message 4 in thread

Dimitri wrote:

  Hi,


    I am writing HTTP server for my needs using QT4, and while doing some 
testing and benchmarking
    using Apache's ab, i found that my server cannot handle concurrent 
requests.

    When concurrency is 1, everything is great, and it works 20% faster than 
apache.
    When i set concurrency to > 1, i get the following error:
    apr_recv: An existing connection was forcibly closed by the remote host. 
(730054)


  I understand you set concurrency in Apache's "ab" benchmarking tool using 
the "-c" option, and that message you're showing us is emitted by "ab".



Yes, by ab. Looks like server socket cannot accept two connections if
those are concurrent.


    So my question is how does one handle concurrent requests with 
QTcpServer?


  Examples are provided with Qt and the documentation explains how to use 
the QTcpServer class:
      http://doc.trolltech.com/4.3/qtcpserver.html
  Try modifying one of the examples to fit your needs. Doesn't it work for 
you?


That's what i do, everything as described. On newConnection() i get
nextPendingConnection() and work with socket. and with browser, and
ab/concurrency set to 1 everything is fine.

But QTcpServer design is event driven, which means as i understand that
every signal/slot is called by event loop, sequentially, one after another.

And here i don't quite understand how to work with concurrent requests.
I was thinking about putting all procession in threads, but i am not
sure if this would help.  Even if i serve 10 bytes page it still fails.

Maybe it is not going to cause any troubles in production, but i still
wanted to clear this out, if it is my fault, or maybe this is just the
way it works.

If someone with deep knowledge of how it works could give me a pointer,
i would really appreciate it.

Thanks,
Yuriy

Here is the simplified server's source code

QHttpServer::QHttpServer( int p, QObject* parent )
: QTcpServer(parent),
      port(p)
{
   connect( this, SIGNAL( newConnection() ), this,
SLOT(onNewConnection() ) );
}

bool QHttpServer::start()
{
    if( !listen(QHostAddress::Any, port) )
    {
        qDebug() << "Could not start server: " << errorString();
        return false;
    }
    return true;
}

void QHttpServer::onNewConnection()
{
    QTcpSocket *clientConnection = nextPendingConnection();
    connect(clientConnection, SIGNAL(disconnected()),
            this, SLOT( connectionClosed() ));

    connect( clientConnection, SIGNAL( readyRead() ), this, SLOT(
onDataRecieve() ) );

    mCurrentSocket = clientConnection;
    disconnected = false;
}

void QHttpServer::connectionClosed()
{
    mCurrentSocket->deleteLater();
    disconnected = true;
}

void QHttpServer::onDataRecieve()
{

    if(disconnected)
    {
        return;
    }

    ///////////
        .........
    read/write from/to socket

    //////////

        mCurrentSocket->disconnectFromHost();
}

void QHttpServer::discardClient()
{
    mCurrentSocket->disconnectFromHost();
    emit endConnect();
}


--
 [ signature omitted ] 

Message 5 in thread

Hi,

> That's what i do, everything as described. On newConnection() i get
> nextPendingConnection() and work with socket. and with browser, and
> ab/concurrency set to 1 everything is fine.
> 
> But QTcpServer design is event driven, which means as i understand that
> every signal/slot is called by event loop, sequentially, one after another.

First signals/slots have nothing to do with events and the event loop, at 
least in the case of direct connections:
	http://doc.trolltech.com/4.3/signalsandslots.html
On the other hand it's true that queued connections introduced in Qt 4.3 are 
based on the event loop.

Anyway, there's nothing specific to the event loop here. Processors execute 
instructions sequentially. The network interface receives bits sequentially 
too. Everything is done sequentially. Concurrency does not mean that data is 
somehow received at exactly the same time by the network interface, or that 
the processor is processing two requests in parallel at the exact same moment.

> [...]
> Here is the simplified server's source code
> [...]
> void QHttpServer::onNewConnection()
> {
>     QTcpSocket *clientConnection = nextPendingConnection();
>     connect(clientConnection, SIGNAL(disconnected()),
>             this, SLOT( connectionClosed() ));
> 
>     connect( clientConnection, SIGNAL( readyRead() ), this, SLOT(
> onDataRecieve() ) );
> 
>     mCurrentSocket = clientConnection;
>     disconnected = false;
> }

There cannot be one current socket when processing concurrent requests. I 
think that's the cause of all your problems: variable "mCurrentSocket" will be 
reset whenever "onNewConnection()" is called, potentially before 
"deleteLater()" is called on the original "mCurrentSocket" in 
"connectionClosed()".

--
 [ signature omitted ] 

Message 6 in thread

Dimitri,

Thank you for clarifications. Now that you said it became obvious to me too
where the problem is.

Yuriy



> Hi,
>
>> That's what i do, everything as described. On newConnection() i get
>> nextPendingConnection() and work with socket. and with browser, and
>> ab/concurrency set to 1 everything is fine.
>>
>> But QTcpServer design is event driven, which means as i understand that
>> every signal/slot is called by event loop, sequentially, one after 
>> another.
>
> First signals/slots have nothing to do with events and the event loop, at 
> least in the case of direct connections:
> http://doc.trolltech.com/4.3/signalsandslots.html
> On the other hand it's true that queued connections introduced in Qt 4.3 
> are based on the event loop.
>
> Anyway, there's nothing specific to the event loop here. Processors 
> execute instructions sequentially. The network interface receives bits 
> sequentially too. Everything is done sequentially. Concurrency does not 
> mean that data is somehow received at exactly the same time by the network 
> interface, or that the processor is processing two requests in parallel at 
> the exact same moment.
>
>> [...]
>> Here is the simplified server's source code
>> [...]
>> void QHttpServer::onNewConnection()
>> {
>>     QTcpSocket *clientConnection = nextPendingConnection();
>>     connect(clientConnection, SIGNAL(disconnected()),
>>             this, SLOT( connectionClosed() ));
>>
>>     connect( clientConnection, SIGNAL( readyRead() ), this, SLOT(
>> onDataRecieve() ) );
>>
>>     mCurrentSocket = clientConnection;
>>     disconnected = false;
>> }
>
> There cannot be one current socket when processing concurrent requests. I 
> think that's the cause of all your problems: variable "mCurrentSocket" 
> will be reset whenever "onNewConnection()" is called, potentially before 
> "deleteLater()" is called on the original "mCurrentSocket" in 
> "connectionClosed()".
>
> --
> Dimitri 


--
 [ signature omitted ]