Netzwerkprogrammierung mit Qt
Das Modul Qt Network bietet Klassen, mit denen Sie TCP/IP-Clients und -Server schreiben können. Es bietet Klassen auf niedrigerer Ebene wie QTcpSocket, QTcpServer und QUdpSocket, die Netzwerkkonzepte auf niedriger Ebene darstellen, und Klassen auf hoher Ebene wie QNetworkRequest, QNetworkReply und QNetworkAccessManager, um Netzwerkoperationen unter Verwendung gängiger Protokolle durchzuführen.
Qt-Klassen für die Netzwerkprogrammierung
Die Seite Qt Network C++ Classes Seite enthält eine Liste der C++-Klassen in Qt Network.
High-Level-Netzwerkoperationen für HTTP
Die Netzwerkzugriffs-API ist eine Sammlung von Klassen zur Durchführung gängiger Netzwerkoperationen. Die API bietet eine Abstraktionsschicht über den spezifischen Operationen und Protokollen, die verwendet werden (z. B. das Abrufen und Senden von Daten über HTTP), und stellt nur Klassen, Funktionen und Signale für allgemeine oder hochrangige Konzepte zur Verfügung.
Netzwerkanfragen werden durch die Klasse QNetworkRequest repräsentiert, die auch als allgemeiner Container für Informationen dient, die mit einer Anfrage verbunden sind, wie z. B. alle Header-Informationen und die verwendete Verschlüsselung. Die bei der Erstellung eines Anfrageobjekts angegebene URL bestimmt das für eine Anfrage verwendete Protokoll. Derzeit werden HTTP- und lokale Datei-URLs für das Hoch- und Herunterladen unterstützt.
Die Koordination der Netzwerkoperationen wird von der Klasse QNetworkAccessManager übernommen. Sobald eine Anfrage erstellt wurde, wird diese Klasse verwendet, um sie zu versenden und Signale auszusenden, um über ihren Fortschritt zu berichten. Der Manager koordiniert auch die Verwendung von cookies zur Speicherung von Daten auf dem Client, Authentifizierungsanfragen und die Verwendung von Proxys.
Antworten auf Netzwerkanfragen werden durch die Klasse QNetworkReply repräsentiert; diese werden von QNetworkAccessManager erstellt, wenn eine Anfrage versandt wird. Die von QNetworkReply bereitgestellten Signale können verwendet werden, um jede Antwort einzeln zu überwachen, oder Entwickler können stattdessen die Signale des Managers für diesen Zweck verwenden und Verweise auf Antworten verwerfen. Da QNetworkReply eine Unterklasse von QIODevice ist, können Antworten synchron oder asynchron behandelt werden, d.h. als blockierende oder nicht-blockierende Operationen.
Jede Anwendung oder Bibliothek kann eine oder mehrere Instanzen von QNetworkAccessManager erstellen, um die Netzwerkkommunikation abzuwickeln.
Verwendung von TCP mit QTcpSocket und QTcpServer
TCP (Transmission Control Protocol) ist ein Low-Level-Netzwerkprotokoll, das von den meisten Internetprotokollen, einschließlich HTTP und FTP, für die Datenübertragung verwendet wird. Es ist ein zuverlässiges, stromorientiertes, verbindungsorientiertes Transportprotokoll. Es eignet sich besonders gut für die kontinuierliche Übertragung von Daten.
Die Klasse QTcpSocket bietet eine Schnittstelle für TCP. Mit QTcpSocket können Sie sowohl Standard-Netzwerkprotokolle wie POP3, SMTP und NNTP als auch eigene Protokolle implementieren.
Bevor eine Datenübertragung beginnen kann, muss eine TCP-Verbindung zu einem entfernten Host und Port aufgebaut werden. Sobald die Verbindung hergestellt ist, sind die IP-Adresse und der Port der Gegenstelle über QTcpSocket::peerAddress() und QTcpSocket::peerPort() verfügbar. Die Gegenstelle kann die Verbindung jederzeit schließen, woraufhin die Datenübertragung sofort beendet wird.
QTcpSocket arbeitet asynchron und sendet Signale, um Statusänderungen und Fehler zu melden, genau wie QNetworkAccessManager. Es stützt sich auf die Ereignisschleife, um eingehende Daten zu erkennen und ausgehende Daten automatisch zu spülen. Sie können mit QTcpSocket::write() Daten in den Socket schreiben und mit QTcpSocket::read() Daten lesen. QTcpSocket stellt zwei unabhängige Datenströme dar: einen zum Lesen und einen zum Schreiben.
Da QTcpSocket von QIODevice erbt, können Sie es mit QTextStream und QDataStream verwenden. Wenn Sie von QTcpSocket lesen, müssen Sie sicherstellen, dass genügend Daten verfügbar sind, indem Sie vorher QTcpSocket::bytesAvailable() aufrufen.
Wenn Sie eingehende TCP-Verbindungen verarbeiten müssen (z. B. in einer Serveranwendung), verwenden Sie die Klasse QTcpServer. Rufen Sie QTcpServer::listen() auf, um den Server einzurichten, und verbinden Sie sich mit dem Signal QTcpServer::newConnection(), das für jeden Client, der sich verbindet, einmal ausgegeben wird. Rufen Sie in Ihrem Slot QTcpServer::nextPendingConnection() auf, um die Verbindung zu akzeptieren, und verwenden Sie das zurückgegebene QTcpSocket, um mit dem Client zu kommunizieren.
Obwohl die meisten Funktionen asynchron arbeiten, ist es möglich, QTcpSocket synchron (d.h. blockierend) zu verwenden. Um ein blockierendes Verhalten zu erhalten, rufen Sie die waitFor...()-Funktionen von QTcpSocket auf; diese halten den aufrufenden Thread an, bis ein Signal ausgegeben wurde. Rufen Sie z. B. nach dem Aufruf der nicht blockierenden Funktion QTcpSocket::connectToHost() QTcpSocket::waitForConnected() auf, um den Thread zu blockieren, bis das Signal connected() ausgegeben wurde.
Synchrone Sockets führen oft zu Code mit einem einfacheren Kontrollfluss. Der Hauptnachteil des waitFor...()-Ansatzes ist, dass Ereignisse nicht verarbeitet werden, während eine waitFor...()-Funktion blockiert. Wenn dies im GUI-Thread verwendet wird, kann dies die Benutzeroberfläche der Anwendung einfrieren. Aus diesem Grund empfehlen wir, dass Sie synchrone Sockets nur in Nicht-GUI-Threads verwenden. Bei synchroner Verwendung von QTcpSocket ist keine Ereignisschleife erforderlich.
Die Fortune-Client- und Fortune-Server-Beispiele zeigen, wie Sie QTcpSocket und QTcpServer verwenden, um TCP-Client-Server-Anwendungen zu schreiben. Siehe auch Blocking Fortune Client für ein Beispiel zur Verwendung eines synchronen QTcpSocket in einem separaten Thread (ohne Verwendung einer Ereignisschleife) und Threaded Fortune Server für ein Beispiel für einen Multithread-TCP-Server mit einem Thread pro aktivem Client.
Verwendung von UDP mit QUdpSocket
UDP (User Datagram Protocol) ist ein leichtes, unzuverlässiges, datagrammorientiertes, verbindungsloses Protokoll. Es kann verwendet werden, wenn die Zuverlässigkeit nicht wichtig ist. Zum Beispiel könnte ein Server, der die Uhrzeit meldet, UDP wählen. Wenn ein Datagramm mit der Uhrzeit verloren geht, kann der Client einfach eine neue Anfrage stellen.
Mit der Klasse QUdpSocket können Sie UDP-Datagramme senden und empfangen. Sie erbt QAbstractSocket und teilt daher den größten Teil der Schnittstelle von QTcpSocket. Der Hauptunterschied besteht darin, dass QUdpSocket Daten als Datagramme und nicht als kontinuierlichen Datenstrom überträgt. Kurz gesagt ist ein Datagramm ein Datenpaket von begrenzter Größe (normalerweise kleiner als 512 Byte), das neben den zu übertragenden Daten auch die IP-Adresse und den Port des Absenders und des Empfängers des Datagramms enthält.
QUdpSocket unterstützt IPv4-Broadcasting. Broadcasting wird häufig verwendet, um Netzwerkerkennungsprotokolle zu implementieren, z. B. um herauszufinden, welcher Host im Netzwerk über den meisten freien Festplattenspeicherplatz verfügt. Ein Host sendet ein Datagramm in das Netz, das alle anderen Hosts empfangen. Jeder Host, der eine Anfrage erhält, sendet daraufhin eine Antwort an den Absender mit seinem aktuellen freien Speicherplatz zurück. Der Absender wartet, bis er Antworten von allen Hosts erhalten hat, und kann dann den Server mit dem meisten freien Speicherplatz zum Speichern von Daten auswählen. Um ein Datagramm zu senden, schicken Sie es einfach an die spezielle Adresse QHostAddress::Broadcast (255.255.255.255) oder an die Broadcast-Adresse Ihres lokalen Netzwerks.
QUdpSocket::bind() bereitet den Socket für die Annahme eingehender Datagramme vor, ähnlich wie QTcpServer::listen() für TCP-Server. Immer wenn ein oder mehrere Datagramme ankommen, gibt QUdpSocket das Signal readyRead() aus. Rufen Sie QUdpSocket::readDatagram() auf, um das Datagramm zu lesen.
Die Beispiele Broadcast Sender und Broadcast Receiver zeigen, wie man einen UDP-Sender und einen UDP-Empfänger mit Qt schreibt.
QUdpSocket Qt unterstützt auch Multicasting. Die Beispiele Multicast-Sender und Multicast-Empfänger zeigen, wie man UDP-Multicast-Clients schreibt.
Auflösen von Host-Namen mit QHostInfo
Bevor eine Netzwerkverbindung hergestellt wird, führen QTcpSocket und QUdpSocket eine Namenssuche durch, bei der der Hostname, zu dem eine Verbindung aufgebaut werden soll, in eine IP-Adresse übersetzt wird. Dieser Vorgang wird normalerweise über das DNS-Protokoll (Domain Name Service) durchgeführt.
QHostInfo bietet eine statische Funktion, mit der Sie selbst eine solche Suche durchführen können. Durch den Aufruf von QHostInfo::lookupHost() mit einem Hostnamen, einem Zeiger auf QObject und einer Slot-Signatur führt QHostInfo die Namenssuche durch und ruft den angegebenen Slot auf, wenn die Ergebnisse fertig sind. Die eigentliche Suche wird in einem separaten Thread durchgeführt, wobei die betriebssystemeigenen Methoden zur Durchführung von Namenssuchen verwendet werden.
QHostInfo bietet auch eine statische Funktion namens QHostInfo::fromName(), die den Hostnamen als Argument nimmt und die Ergebnisse zurückgibt. In diesem Fall wird die Namenssuche im gleichen Thread wie der Aufrufer durchgeführt. Diese Überladung ist nützlich für Nicht-GUI-Anwendungen oder für die Durchführung von Namensnachforschungen in einem separaten, nicht-GUI-Thread. (Der Aufruf dieser Funktion in einem GUI-Thread kann dazu führen, dass Ihre Benutzeroberfläche einfriert, während die Funktion blockiert, während sie die Suche durchführt).
Unterstützung für Netzwerk-Proxies
Die Netzwerkkommunikation mit Qt kann über Proxies erfolgen, die den Netzwerkverkehr zwischen lokalen und entfernten Verbindungen umleiten oder filtern.
Individuelle Proxies werden durch die Klasse QNetworkProxy repräsentiert, die zur Beschreibung und Konfiguration der Verbindung zu einem Proxy verwendet wird. Es werden Proxy-Typen unterstützt, die auf verschiedenen Ebenen der Netzwerkkommunikation arbeiten, wobei die Unterstützung von SOCKS 5 das Proxying von Netzwerkverkehr auf einer niedrigen Ebene ermöglicht und HTTP- und FTP-Proxying auf Protokollebene funktioniert. Siehe QNetworkProxy::ProxyType für weitere Informationen.
Proxying kann pro Socket oder für die gesamte Netzwerkkommunikation in einer Anwendung aktiviert werden. Ein neu geöffneter Socket kann dazu gebracht werden, einen Proxy zu verwenden, indem seine Funktion QAbstractSocket::setProxy() aufgerufen wird, bevor er verbunden wird. Anwendungsweites Proxying kann für alle nachfolgenden Socket-Verbindungen durch die Verwendung der Funktion QNetworkProxy::setApplicationProxy() aktiviert werden.
Proxy-Fabriken werden verwendet, um Richtlinien für die Verwendung von Proxys zu erstellen. QNetworkProxyFactory liefert Proxys auf der Grundlage von Abfragen für bestimmte Proxy-Typen. Die Abfragen selbst sind in QNetworkProxyQuery Objekten kodiert, die es ermöglichen, Proxys anhand von Schlüsselkriterien auszuwählen, wie z. B. dem Zweck des Proxys (TCP, UDP, TCP-Server, URL-Anfrage), dem lokalen Port, dem entfernten Host und Port und dem verwendeten Protokoll (HTTP, FTP usw.).
QNetworkProxyFactory::proxyForQuery() wird verwendet, um die Fabrik direkt abzufragen. Eine anwendungsweite Proxy-Richtlinie kann durch Übergabe einer Fabrik an QNetworkProxyFactory::setApplicationProxyFactory() implementiert werden, und eine benutzerdefinierte Proxy-Richtlinie kann durch Unterklassifizierung von QNetworkProxyFactory erstellt werden; Einzelheiten finden Sie in der Klassendokumentation.
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.