I am interested in how QTcpServer works behind the scenes regarding threads and blocking. QTcpServer has a listen() method which returns immediately. If listening started successfully the server will emit the signal newConnection(). I'm interested into how is the server listening (is it on the main thread) when the listen() method has returned. The usual example of a console application with a QTcpServer is something like this:
//main.cpp
int main(int argc, char* argv[])
{
QCoreApplication app;
MyServer server;
app.exec();
}
//MyServer.cpp
MyServer::MyServer(QObject *parent) : QObject(parent)
{
this->server = new QTcpServer(this);
connect(server, SIGNAL(newConnection()), this, SLOT(on_newConnection()));
if (!server->listen(QHostAddress::Any, 1234))
//do something in case of error
}
void MyServer::on_newConnection()
{
QTcpSocket* socket = server->nextPendingConnection();
//do some communication...
}
Is QTcpServer dependent upon a QCoreApplication (or maybe a QRunLoop) existing and running to receive network events. Can it work properly without a QCoreApplication::exec() being called?
I've been drilling through the source code of the
QtCoreandQtNetworkmodules.Aperantly,
QTcpServercan work in two modes: synchronous and asynchronous.In synchronous mode after calling
listen()the caller can callwaitForNewConnection()which is a blocking method (the thread will sleep until someone connects to the listening port). This wayQTcpServercan work in a thread without an event loop.In asynchronous mode
QTcpServerwill emit thenewConnection()signal when a new connection was accepted. But to be able to do this there must be an event loop runing. Underlying theQCoreApplicationare theQEventLoopandQAbstractEventDispatcher(an abstract class, concrete type is dependent on the OS, for exampleQEventDispatcherUNIX). This event dispatcher can monitor for conditions on sockets (represented by file descriptors). It has a methodregisterSocketNotifier(QSocketNotifier*). This method is called by the constructor of theQSocketNotifierclass, whichQTcpServercreates an instance of every timelisten()is called. The only system call that is called when theQTcpServer::listen()is invoked is, of course,listen()which just returns immediately, all the real magic happens when the event loop starts running. The event loop (using the dispatcher) will monitor if there is a certain condition on sockets that have been registered. It calls theselect()system call which receives one or more file descriptors to be monitored (by the kernel) for certain conditions (if there is data to be read, if data can be written, or if an error has occurred). The call can block the thread until the conditions on sockets are met, or it can return after some amount of time passes and the conditions on sockets were not met. I am not sure if Qt is callingselect()with a waiting time supplied or without (to block indefinitely), I think it is determined in some complicated way and changeable. So when finally the condition on socket has been met, the event dispatcher will notify theQSocketNotifierfor that socket, which will, in tern, notify theQTcpServerwho is listening to the socket, which will accept the connection, and emit thenewConnection()signal.So the
QTcpServerdoes not itself call into the event-loop/socket-monitoring system, but it is dependent upon it via theQSocketNotifierwhich it uses for asynchronous recieving of connections.When synchronous method
waitForNewConnection()is called it just bypasses all theQSocketNotifierstuff and callsaccept()which blocks the thread until there is an incoming connection.