Question

Je suis intéressé par la façon dont QTcpServer fonctionne en coulisses concernant les threads et le blocage. QTcpServer a un listen() méthode qui revient immédiatement.Si l'écoute a démarré avec succès, le serveur émettra le signal newConnection().Je suis intéressé par la manière dont le serveur écoute (est-il sur le thread principal) lorsque le listen() la méthode est revenue.L'exemple habituel d'une application console avec un QTcpServer ressemble à ceci :

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

Est QTcpServer dépendant d'un QCoreApplication (ou peut-être un QRunLoop) existant et en cours d'exécution pour recevoir les événements du réseau.Peut-il fonctionner correctement sans QCoreApplication::exec() être appelé?

Était-ce utile?

La solution

J'ai parcouru le code source du QtCore et QtNetwork modules.

Apparemment, QTcpServer peut fonctionner selon deux modes : synchrone et asynchrone.

Dans synchrone mode après avoir appelé listen() l'appelant peut appeler waitForNewConnection() qui est une méthode de blocage (le thread restera en veille jusqu'à ce que quelqu'un se connecte au port d'écoute).Par ici QTcpServer peut fonctionner dans un thread sans boucle d'événements.

Dans asynchrone mode QTcpServer émettra le newConnection() signal lorsqu'une nouvelle connexion a été acceptée.Mais pour pouvoir faire cela, il doit y avoir une boucle d'événements en cours d'exécution.Sous-jacent au QCoreApplication sont les QEventLoop et QAbstractEventDispatcher (une classe abstraite, le type concret dépend du système d'exploitation, par exemple QEventDispatcherUNIX).Ce répartiteur d'événements peut surveiller les conditions sur les sockets (représentées par des descripteurs de fichiers).Il a une méthode registerSocketNotifier(QSocketNotifier*).Cette méthode est appelée par le constructeur du QSocketNotifier classe, qui QTcpServer crée une instance de chaque fois listen() est appelé.Le seul appel système appelé lorsque le QTcpServer::listen() est invoqué est, bien sûr, listen() qui revient immédiatement, toute la vraie magie se produit lorsque la boucle d'événements commence à s'exécuter.La boucle d'événements (à l'aide du répartiteur) surveillera s'il existe une certaine condition sur les sockets qui ont été enregistrées.Il appelle le select() appel système qui reçoit un ou plusieurs descripteurs de fichiers à surveiller (par le noyau) pour certaines conditions (s'il y a des données à lire, si des données peuvent être écrites ou si une erreur s'est produite).L'appel peut bloquer le thread jusqu'à ce que les conditions sur les sockets soient remplies, ou il peut revenir après un certain temps et les conditions sur les sockets ne sont pas remplies.Je ne sais pas si Qt appelle select() avec un temps d'attente fourni ou sans (pour bloquer indéfiniment), je pense qu'il est déterminé de manière compliquée et modifiable.Ainsi, lorsque la condition sur le socket sera finalement remplie, le répartiteur d'événements en informera le QSocketNotifier pour cette prise, qui, en fin de compte, informera le QTcpServer qui écoute la socket, qui acceptera la connexion et émettra le newConnection() signal.


Alors le QTcpServer ne fait pas lui-même appel au système de surveillance des boucles d'événements/des sockets, mais il en dépend via le QSocketNotifier qu'il utilise pour la réception asynchrone des connexions.

Lorsque la méthode synchrone waitForNewConnection() on l'appelle, il contourne simplement tous les QSocketNotifier trucs et appels accept() qui bloque le thread jusqu'à ce qu'il y ait une connexion entrante.

Autres conseils

La plupart des fonctionnalités « en coulisses » de Qt se produisent dans la boucle d'événements principale de QCoreApplication :signaux/emplacements, minuteries, etc.
Un exemple serait JavaScript : vous liez un événement, mais la boucle d'événement est traitée par le navigateur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top