Pregunta

Estoy interesado en cómo funciona QTcpServer detrás de escena con respecto a subprocesos y bloqueo. QTcpServer tiene un listen() método que regresa inmediatamente.Si la escucha se inició correctamente, el servidor emitirá la señal. newConnection().Estoy interesado en cómo escucha el servidor (¿está en el hilo principal) cuando el listen() El método ha regresado.El ejemplo habitual de una aplicación de consola con QTcpServer es algo como esto:

//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 dependiente de un QCoreApplication (o tal vez un QRunLoop) existente y ejecutándose para recibir eventos de red.¿Puede funcionar correctamente sin un QCoreApplication::exec() ¿siendo llamado?

¿Fue útil?

Solución

He estado profundizando en el código fuente del QtCore y QtNetwork módulos.

Aparentemente, QTcpServer Puede funcionar en dos modos: sincrónico y asincrónico.

En sincrónico modo después de llamar listen() la persona que llama puede llamar waitForNewConnection() que es un método de bloqueo (el hilo dormirá hasta que alguien se conecte al puerto de escucha).Por aquí QTcpServer puede funcionar en un hilo sin un bucle de eventos.

En asincrónico modo QTcpServer emitirá el newConnection() señal cuando se aceptó una nueva conexión.Pero para poder hacer esto debe haber un bucle de eventos en ejecución.Subyacente al QCoreApplication son los QEventLoop y QAbstractEventDispatcher (una clase abstracta, el tipo concreto depende del sistema operativo, por ejemplo QEventDispatcherUNIX).Este despachador de eventos puede monitorear las condiciones en los sockets (representados por descriptores de archivos).tiene un metodo registerSocketNotifier(QSocketNotifier*).Este método es llamado por el constructor del QSocketNotifier clase, que QTcpServer crea una instancia de cada vez listen() se llama.La única llamada al sistema que se llama cuando el QTcpServer::listen() se invoca es, por supuesto, listen() que regresa inmediatamente, toda la magia real ocurre cuando el bucle de eventos comienza a ejecutarse.El bucle de eventos (usando el despachador) monitoreará si existe una determinada condición en los sockets que se han registrado.llama al select() llamada al sistema que recibe uno o más descriptores de archivos para ser monitoreados (por el kernel) 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 de los sockets, o puede regresar después de que pase un tiempo y no se cumplan las condiciones de los sockets.No estoy seguro si Qt está llamando select() con un tiempo de espera proporcionado o sin (para bloquear indefinidamente), creo que se determina de alguna manera complicada y modificable.Entonces, cuando finalmente se cumpla la condición en el socket, el despachador de eventos notificará al QSocketNotifier para ese enchufe, que, a su vez, notificará al QTcpServer quién está escuchando el socket, que aceptará la conexión y emitirá el newConnection() señal.


Entonces el QTcpServer no llama por sí mismo al sistema de monitoreo de bucle de eventos/socket, pero depende de él a través del QSocketNotifier que utiliza para la recepción asincrónica de conexiones.

Cuando el método sincrónico waitForNewConnection() se llama simplemente pasa por alto todos los QSocketNotifier cosas y llamadas accept() que bloquea el hilo hasta que haya una conexión entrante.

Otros consejos

La mayor parte de la funcionalidad "detrás de escena" de Qt ocurre dentro del bucle de eventos principal de QCoreApplication:señales/ranuras, temporizadores, etc.
Un ejemplo sería JavaScript: vincula un evento, pero el navegador procesa el bucle de eventos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top