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