Frage

Mich interessiert, wie QTcpServer hinter den Kulissen in Bezug auf Threads und Blockierung funktioniert. QTcpServer hat ein listen() Methode, die sofort zurückkehrt.Wenn das Abhören erfolgreich gestartet wurde, sendet der Server das Signal newConnection().Mich interessiert, wie der Server zuhört (ist er im Hauptthread), wenn der listen() Methode ist zurückgekehrt.Das übliche Beispiel einer Konsolenanwendung mit einem QTcpServer sieht etwa so aus:

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

Ist QTcpServer abhängig von a QCoreApplication (oder vielleicht ein QRunLoop) vorhanden und ausgeführt, um Netzwerkereignisse zu empfangen.Kann es ohne a richtig funktionieren? QCoreApplication::exec() gerufen werden?

War es hilfreich?

Lösung

Ich habe den Quellcode des durchforstet QtCore Und QtNetwork Module.

Offensichtlich, QTcpServer kann in zwei Modi arbeiten: synchron Und asynchron.

In synchron Modus nach dem Aufruf listen() Der Anrufer kann anrufen waitForNewConnection() Dabei handelt es sich um eine Blockierungsmethode (der Thread ruht, bis sich jemand mit dem Überwachungsport verbindet).Hier entlang QTcpServer kann in einem Thread ohne Ereignisschleife arbeiten.

In asynchron Modus QTcpServer wird das aussenden newConnection() Signal, wenn eine neue Verbindung angenommen wurde.Um dies tun zu können, muss jedoch eine Ereignisschleife ausgeführt werden.Dahinter verbirgt sich die QCoreApplication sind die QEventLoop Und QAbstractEventDispatcher (Eine abstrakte Klasse, der konkrete Typ hängt beispielsweise vom Betriebssystem ab QEventDispatcherUNIX).Dieser Ereignis-Dispatcher kann Bedingungen für Sockets überwachen (dargestellt durch Dateideskriptoren).Es hat eine Methode registerSocketNotifier(QSocketNotifier*).Diese Methode wird vom Konstruktor der aufgerufen QSocketNotifier Klasse, die QTcpServer Erstellt von jedem Mal eine Instanz listen() wird genannt.Der einzige Systemaufruf, der aufgerufen wird, wenn die QTcpServer::listen() aufgerufen wird, ist natürlich listen() das einfach sofort zurückkehrt, die ganze wahre Magie passiert, wenn die Ereignisschleife zu laufen beginnt.Die Ereignisschleife (mithilfe des Dispatchers) überwacht, ob bei registrierten Sockets eine bestimmte Bedingung vorliegt.Es nennt die select() Systemaufruf, der einen oder mehrere Dateideskriptoren empfängt, die (vom Kernel) auf bestimmte Bedingungen überwacht werden sollen (ob Daten gelesen werden müssen, ob Daten geschrieben werden können oder ob ein Fehler aufgetreten ist).Der Aufruf kann den Thread blockieren, bis die Bedingungen für Sockets erfüllt sind, oder er kann zurückkehren, nachdem eine gewisse Zeit verstrichen ist und die Bedingungen für Sockets nicht erfüllt wurden.Ich bin nicht sicher, ob Qt anruft select() Mit oder ohne Wartezeit (auf unbestimmte Zeit blockieren), ich denke, es ist auf eine komplizierte Art und Weise festgelegt und veränderbar.Wenn also schließlich die Bedingung für den Socket erfüllt ist, benachrichtigt der Ereignis-Dispatcher den QSocketNotifier für diesen Socket, der wiederum den benachrichtigt QTcpServer Wer hört auf den Socket, der die Verbindung akzeptiert und die ausgibt newConnection() Signal.


Also die QTcpServer ruft selbst nicht das Ereignisschleifen-/Socket-Überwachungssystem auf, sondern ist über das darauf angewiesen QSocketNotifier die es zum asynchronen Empfangen von Verbindungen verwendet.

Bei der synchronen Methode waitForNewConnection() heißt es umgeht einfach alles QSocketNotifier Sachen und Anrufe accept() Dadurch wird der Thread blockiert, bis eine eingehende Verbindung besteht.

Andere Tipps

Die meisten Qt-Funktionen „hinter den Kulissen“ finden innerhalb der Hauptereignisschleife von QCoreApplication statt:Signale/Slots, Timer usw.
Ein Beispiel wäre JavaScript – Sie binden ein Ereignis, aber die Ereignisschleife wird vom Browser verarbeitet.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top