SCXML-FTP-Client
Implementiert einen einfachen FTP-Client mithilfe einer Zustandsmaschine.
Der FTP-Client nutzt „ Qt SCXML “, um einen FTP-Client zu implementieren, der mit einem FTP-Dienst kommunizieren kann, indem er aus Zustandsmaschinenereignissen übersetzte FTP-Steuerungsnachrichten sendet und Serverantworten in Zustandsmaschinenereignisse übersetzt. Die vom FTP-Server empfangenen Daten werden auf der Konsole ausgegeben.
RFC 959 spezifiziert Zustandsdiagramme für die Befehlsverarbeitung des FTP-Clients. Diese lassen sich leicht in SCXML übersetzen, um die Vorteile der verschachtelten Zustände von SCXML zu nutzen. Die Verbindungen zwischen Client und Server sowie die Datenübertragung werden mithilfe von C++ implementiert. Darüber hinaus kommen Qt-Signale und -Slots zum Einsatz.
Die Zustandsmaschine verfügt über die folgenden Zustände:

- I als Ausgangszustand.
- B für das Senden von Befehlen.
- S für Erfolg.
- F für Fehlschlag.
- W für das Warten auf eine Antwort.
- P für die Eingabe eines Passworts auf Anfrage des Servers.
Die Zustandsmaschine ist in der Datei „simpleftp.scxml“ definiert und in die Klasse „ FtpClient “ kompiliert, die die Logik des FTP-Protokolls implementiert. Sie reagiert auf Benutzereingaben und auf Antworten aus dem Kontrollkanal, indem sie Zustände wechselt und externe Ereignisse sendet. Darüber hinaus implementieren wir eine Klasse „ FtpControlChannel “ und eine Klasse „ FtpDataChannel “, die TCP-Sockets und -Server verwalten und Zeilenenden konvertieren.
Ausführen des Beispiels
Sie können das Beispiel ausführen unter:
- Qt Creator
Öffnen Sie den Modus „ Welcome “ und wählen Sie das Beispiel unter „ Examples “ aus. Weitere Informationen finden Sie unter Qt Creator: Tutorial: Erstellen und Ausführen.
- Qt Extension for Visual Studio Code
Führen Sie den Befehl „ Qt: Open Qt examples “ aus dem Verzeichnis „ Command Palette “ aus und wählen Sie das Beispiel aus der Liste aus. Weitere Informationen finden Sie unter Qt Extension for Visual Studio Code: Tutorial: Erstellen und Ausführen.
Kompilieren der Zustandsmaschine
Wir verknüpfen das Modul „ Qt SCXML “, indem wir die folgende Zeile zu den Build-Dateien des Projekts hinzufügen.
Mit qmake fügen wir Folgendes zu ftpclient.pro hinzu
QT = core scxml networkAnschließend legen wir die zu kompilierende Zustandsmaschine fest:
STATECHARTS += simpleftp.scxmlMit CMake fügen wir Folgendes zur Datei „CMakeLists.txt“ hinzu
find_package(Qt6 REQUIRED COMPONENTS Core Network Scxml)
target_link_libraries(ftpclient PRIVATE
Qt6::Core
Qt6::Network
Qt6::Scxml
)Anschließend legen wir die zu kompilierende Zustandsmaschine fest:
qt6_add_statecharts(ftpclient
simpleftp.scxml
)Der „ Qt SCXML “-Compiler ( qscxmlc) wird automatisch ausgeführt, um die Dateien „simpleftp.h“ und „simpleftp.cpp“ zu generieren und sie dem Projekt entsprechend als Header- und Quelldateien hinzuzufügen.
Instanziierung der Zustandsmaschine
Wir instanziieren die generierte Klasse „ FtpClient “ sowie die Klassen „ FtpDataChannel “ und „ FtpControlChannel “ in der Datei „main.cpp “:
#include "ftpcontrolchannel.h"
#include "ftpdatachannel.h"
#include "simpleftp.h"
...
int main(int argc, char *argv[])
{
...
QCoreApplication app(argc, argv);
FtpClient ftpClient;
FtpDataChannel dataChannel;
FtpControlChannel controlChannel;
...Kommunikation mit einem FTP-Server
Wir geben alle vom Server abgerufenen Daten auf der Konsole aus:
QObject::connect(&dataChannel, &FtpDataChannel::dataReceived,
[](const QByteArray &data) {
std::cout << data.constData() << std::flush;
});Wir wandeln die Antworten des Servers in Zustandsmaschinenereignisse um:
QObject::connect(&controlChannel, &FtpControlChannel::reply, &ftpClient,
[&ftpClient](int code, const QString ¶meters) {
ftpClient.submitEvent(QString("reply.%1xx")
.arg(code / 100), parameters);
});Wir wandeln Befehle aus der Zustandsmaschine in FTP-Steuerungsnachrichten um:
ftpClient.connectToEvent("submit.cmd", &controlChannel,
[&controlChannel](const QScxmlEvent &event) {
controlChannel.command(event.name().mid(11).toUtf8(),
event.data().toMap()["params"].toByteArray());
});Wir senden Befehle, um uns als anonymer Benutzer beim FTP-Server anzumelden, einen Port für die Datenverbindung anzugeben und eine Datei abzurufen:
QList<Command> commands({
{"cmd.USER", "anonymous"},// login
{"cmd.PORT", ""}, // announce port for data connection,
// args added below.
{"cmd.RETR", file} // retrieve a file
});Wir legen fest, dass der FTP-Client den nächsten Befehl senden soll, sobald der Zustand B erreicht wird:
ftpClient.connectToState("B", QScxmlStateMachine::onEntry([&]() {
if (commands.isEmpty()) {
app.quit();
return;
}
Command command = commands.takeFirst();
qDebug() << "Posting command" << command.cmd << command.args;
ftpClient.submitEvent(command.cmd, command.args);
}));Wir legen fest, dass der FTP-Client eine leere Zeichenfolge als Passwort senden soll, falls der Server danach fragt:
ftpClient.connectToState("P", QScxmlStateMachine::onEntry([&ftpClient]() {
qDebug() << "Sending password";
ftpClient.submitEvent("cmd.PASS", QString());
}));Abschließend stellen wir eine Verbindung zu dem FTP-Server her, der als erstes Argument der Methode angegeben wurde, und rufen die als zweites Argument angegebene Datei ab:
controlChannel.connectToServer(server);
QObject::connect(&controlChannel, &FtpControlChannel::opened, &dataChannel,
[&](const QHostAddress &address, int) {
dataChannel.listen(address);
commands[1].args = dataChannel.portspec();
ftpClient.start();
});Beispielsweise gibt der folgende Aufruf die angegebene Datei vom angegebenen Server aus: ftpclient <server> <file>.
© 2026 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.