2012-07-26 35 views
8

Me interesa saber cómo funciona QTcpServer entre bastidores en lo que respecta a los hilos y el bloqueo. QTcpServer tiene un método listen() que devuelve inmediatamente. Si la escucha comenzó correctamente, el servidor emitirá la señal newConnection(). Me interesa saber cómo está escuchando el servidor (¿está en el hilo principal?) Cuando ha regresado el método listen(). El ejemplo habitual de una aplicación de consola con un QTcpServer es algo como esto:¿Cómo está realmente QTcpServer escuchando conexiones?

//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... 
} 

Es QTcpServer depende de una QCoreApplication (o tal vez un QRunLoop) existentes y en funcionamiento a recive eventos de red. ¿Puede funcionar correctamente sin llamar a QCoreApplication::exec()?

Respuesta

16

He estado explorando el código fuente de los módulos QtCore y QtNetwork.

Aperantly, QTcpServer puede funcionar en dos modos: sincrónica y asíncrono.

En modo sincrónicolisten() después de llamar a la persona que llama puede llamar waitForNewConnection() que es un método de bloqueo (el hilo va a dormir hasta que alguien se conecta al puerto de escucha). De esta forma, QTcpServer puede trabajar en un hilo sin un bucle de evento.

En asíncrono modo QTcpServer emitirá la señal newConnection() cuando una nueva conexión fue aceptada. Pero para poder hacer esto, debe haber un run run de evento. Debajo de QCoreApplication están QEventLoop y QAbstractEventDispatcher (una clase abstracta, tipo concreto depende del SO, por ejemplo QEventDispatcherUNIX). Este despachador de eventos puede monitorear las condiciones en los sockets (representados por los descriptores de archivos). Tiene un método registerSocketNotifier(QSocketNotifier*). Este método es invocado por el constructor de la clase QSocketNotifier, que QTcpServer crea una instancia de cada vez que se llama a listen(). La única llamada al sistema que se invoca cuando se invoca QTcpServer::listen() es, por supuesto, listen(), que simplemente devuelve inmediatamente, toda la magia real ocurre cuando el ciclo de evento comienza a ejecutarse. El bucle de evento (utilizando el despachador) controlará si hay una condición determinada en los sockets que se han registrado. Llama a la llamada al sistema select() que recibe uno o más descriptores de archivos para ser monitoreados (por el núcleo) para ciertas condiciones (si hay datos para leer, si se pueden escribir datos o si se ha producido un error). La llamada puede bloquear el hilo hasta que se cumplan las condiciones en los sockets, o puede volver después de que transcurra cierto tiempo y no se cumplan las condiciones en los sockets. No estoy seguro si Qt está llamando al select() con un tiempo de espera suministrado o sin (para bloquear indefinidamente), creo que está determinado de alguna manera complicada y modificable. Así que cuando finalmente se cumpla la condición en el socket, el despachador de eventos notificará al QSocketNotifier para ese socket, que, a su vez, notificará al QTcpServer que está escuchando el socket, que aceptará la conexión y emitirá la señal newConnection().


Así que la QTcpServer en sí no ponen en el sistema de eventos de lazo/toma de monitoreo, pero es dependiente de ella a través de la QSocketNotifier que utiliza para recieving asíncrona de conexiones.

Cuando se llama al método síncrono waitForNewConnection(), omite todas las cosas QSocketNotifier y llama a accept(), que bloquea el hilo hasta que haya una conexión entrante.

+0

Muy bonito. Ahora entiendo por qué llamar para escuchar antes de ejecutar el ciclo de eventos de aplicaciones en Qt (uso PyQt) resultó en que no obtuve una señal 'newConnection'. Gracias por cavar – Trilarion

0

La mayoría de Qt de "entre bastidores" funcionalidad que sucede dentro de bucle de eventos principal de QCoreApplication: señales/slots, temporizadores, etc.
Un ejemplo sería JavaScript - que ates un evento, pero bucle de eventos es procesada por el navegador.

Cuestiones relacionadas