Wie hört QTcpServer wirklich auf Verbindungen?

8

Ich bin daran interessiert, wie QTcpServer hinter den Kulissen in Bezug auf Threads und Blockierungen arbeitet. QTcpServer hat eine listen() -Methode, die sofort zurückkehrt. Wenn die Überwachung erfolgreich gestartet wurde, gibt der Server das Signal newConnection() aus. Ich bin daran interessiert, wie der Server zuhören (ist es auf den Haupt-Thread), wenn die Methode listen() zurückgegeben hat. Das übliche Beispiel einer Konsolenanwendung mit einem QTcpServer ist etwa so:

%Vor%

Ist QTcpServer abhängig von einem QCoreApplication (oder vielleicht einem QRunLoop ), das vorhanden ist und ausgeführt wird, um Netzwerkereignisse zu empfangen. Kann es richtig funktionieren, ohne dass ein QCoreApplication::exec() aufgerufen wird?

    
irpbc 26.07.2012, 08:28
quelle

2 Antworten

16

Ich habe den Quellcode der Module QtCore und QtNetwork durchgegangen.

Interessanterweise kann QTcpServer in zwei Modi arbeiten: synchron und asynchron .

Im synchronen Modus nach dem Aufruf von listen() kann der Aufrufer waitForNewConnection() aufrufen, was eine blockierende Methode ist (der Thread wird schlafen, bis sich jemand mit dem empfangenden Port verbindet). Auf diese Weise kann QTcpServer in einem Thread ohne Ereignisschleife arbeiten.

Im Modus asynchron wird QTcpServer das Signal newConnection() ausgeben, wenn eine neue Verbindung akzeptiert wurde. Dazu muss jedoch eine Ereignisschleife ausgeführt werden. Dem QCoreApplication liegen die QEventLoop und QAbstractEventDispatcher zugrunde (eine abstrakte Klasse, der konkrete Typ ist abhängig vom Betriebssystem, zB QEventDispatcherUNIX ). Dieser Event-Dispatcher kann Bedingungen auf Sockets überwachen (dargestellt durch Dateideskriptoren). Es hat eine Methode registerSocketNotifier(QSocketNotifier*) . Diese Methode wird vom Konstruktor der Klasse QSocketNotifier aufgerufen, wobei QTcpServer eine Instanz jedes Mal erstellt, wenn listen() aufgerufen wird. Der einzige Systemaufruf, der aufgerufen wird, wenn QTcpServer::listen() aufgerufen wird, ist natürlich listen() , das einfach sofort zurückkehrt. Die eigentliche Magie tritt auf, wenn die Ereignisschleife beginnt. Die Ereignisschleife (mit dem Dispatcher) überwacht, ob eine bestimmte Bedingung für Sockets vorliegt, die registriert wurden. Sie ruft den Systemaufruf select() auf, der einen oder mehrere Dateideskriptoren für bestimmte Bedingungen (vom Kernel) überwacht (wenn Daten gelesen werden sollen, Daten geschrieben werden können oder wenn Ein Fehler ist aufgetreten). Der Aufruf kann den Thread blockieren, bis die Bedingungen für Sockets erfüllt sind, oder er kann nach einiger Zeit zurückkehren und die Bedingungen für Sockets wurden nicht erfüllt. Ich bin mir nicht sicher, ob Qt select() mit einer gelieferten Wartezeit oder ohne (unbegrenzt zu blockieren) anruft, ich denke, dass es in einer komplizierten Weise und veränderbar ist. Wenn die Bedingung für den Socket schließlich erfüllt ist, wird der Event-Dispatcher die QSocketNotifier für diesen Socket benachrichtigen, der wiederum QTcpServer benachrichtigt, wer den Socket abgehört, der die Verbindung akzeptiert und sendet das Signal newConnection() .

Also ruft das QTcpServer nicht selbst das Event-Loop / Socket-Monitoring-System auf, sondern es hängt von ihm über das QSocketNotifier ab, das es für das asynchrone Empfangen von Verbindungen verwendet.

Wenn die synchrone Methode waitForNewConnection() aufgerufen wird, umgeht sie einfach alle QSocketNotifier stuff und ruft accept() auf, was den Thread blockiert, bis eine Verbindung eingeht.

    
irpbc 27.07.2012, 16:31
quelle
0

Die meiste Qt-Funktionalität "hinter den Kulissen" findet innerhalb der Haupt-Event-Schleife von QCoreApplication statt: Signale / Slots, Timer usw.
Ein Beispiel wäre JavaScript - Sie binden ein Ereignis, aber die Ereignisschleife wird vom Browser verarbeitet.

    
friendzis 26.07.2012 12:27
quelle

Tags und Links