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 ]