Client FTP SCXML
Implémente un client FTP simple en utilisant une machine à états.
Le client FTP utilise Qt SCXML pour mettre en œuvre un client FTP qui peut communiquer avec un service FTP en envoyant des messages de contrôle FTP traduits à partir d'événements de machine d'état et en traduisant les réponses du serveur en événements de machine d'état. Les données reçues du serveur FTP sont imprimées sur la console.
LaRFC 959 spécifie des diagrammes d'état pour la gestion des commandes du client FTP. Ils peuvent être facilement traduits en SCXML pour bénéficier des états imbriqués de SCXML. Les connexions entre le client et le serveur et le transfert de données sont mis en œuvre à l'aide de C++. En outre, les signaux et les emplacements Qt sont utilisés.
La machine à états comporte les états suivants :

- I comme état initial.
- B pour l'envoi de commandes.
- S pour succès.
- F pour échec.
- W pour l'attente d'une réponse.
- P pour fournir un mot de passe à la demande du serveur.
La machine à états est spécifiée dans le fichier simpleftp.scxml et compilée dans la classe FtpClient qui met en œuvre la logique du protocole FTP. Elle réagit aux entrées de l'utilisateur et aux réponses du canal de contrôle en changeant d'état et en envoyant des événements externes. En outre, nous mettons en œuvre une classe FtpControlChannel et une classe FtpDataChannel qui gèrent les sockets et les serveurs TCP et convertissent les fins de ligne.
Exécution de l'exemple
Pour exécuter l'exemple à partir de Qt Creatorouvrez le mode Welcome et sélectionnez l'exemple de Examples. Pour plus d'informations, voir Qt Creator: Tutoriel : Construire et exécuter.
Compilation de la machine à états
Nous établissons un lien avec le module Qt SCXML en ajoutant la ligne suivante aux fichiers de compilation du projet.
Avec qmake, nous ajoutons ce qui suit à ftpclient.pro
QT = core scxml network
Nous spécifions ensuite la machine d'état à compiler :
STATECHARTS += simpleftp.scxml
Avec CMake, nous ajoutons ce qui suit au fichier CMakeLists.txt
find_package(Qt6 REQUIRED COMPONENTS Core Network Scxml)
target_link_libraries(ftpclient PRIVATE
Qt6::Core
Qt6::Network
Qt6::Scxml
)Nous spécifions ensuite la machine d'état à compiler :
qt6_add_statecharts(ftpclient
simpleftp.scxml
)Le compilateur Qt SCXML, qscxmlc, est exécuté automatiquement pour générer simpleftp.h et simpleftp.cpp, et pour les ajouter de manière appropriée au projet en tant qu'en-têtes et sources.
Instanciation de la machine à états
Nous instancions la classe FtpClient générée, ainsi que les classes FtpDataChannel et FtpControlChannel dans le fichier 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; ...
Communiquer avec un serveur FTP
Nous imprimons toutes les données extraites du serveur sur la console :
QObject::connect(&dataChannel, &FtpDataChannel::dataReceived, [](const QByteArray &data) { std::cout << data.constData() << std::flush; });
Nous traduisons les réponses du serveur en événements de la machine d'état :
QObject::connect(&controlChannel, &FtpControlChannel::reply, &ftpClient, [&ftpClient](int code, const QString ¶meters) { ftpClient.submitEvent(QString("reply.%1xx") .arg(code / 100), parameters); });
Nous traduisons les commandes de la machine d'état en messages de contrôle FTP :
ftpClient.connectToEvent("submit.cmd", &controlChannel, [&controlChannel](const QScxmlEvent &event) { controlChannel.command(event.name().mid(11).toUtf8(), event.data().toMap()["params"].toByteArray()); });
Nous envoyons des commandes pour nous connecter au serveur FTP en tant qu'utilisateur anonyme, pour annoncer un port pour la connexion de données et pour récupérer un fichier :
QList<Command> commands({ {"cmd.USER", "anonymous"},// login {"cmd.PORT", ""}, // announce port for data connection, // args added below. {"cmd.RETR", file} // retrieve a file });
Nous spécifions que le client FTP doit envoyer la commande suivante lorsqu'il entre dans l'état B :
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) ; })) ;
Nous spécifions que le client FTP doit envoyer une chaîne vide comme mot de passe si le serveur en demande un :
ftpClient.connectToState("P", QScxmlStateMachine::onEntry([&ftpClient]() { qDebug() << "Sending password"; ftpClient.submitEvent("cmd.PASS", QString() ; })) ;
Enfin, nous nous connectons au serveur FTP spécifié comme premier argument de la méthode et récupérons le fichier spécifié comme second argument :
controlChannel.connectToServer(server); QObject::connect(&controlChannel, &FtpControlChannel::opened, &dataChannel, [&](const QHostAddress &address, int) { dataChannel.listen(address); commands[1].args = dataChannel.portspec(); ftpClient.start(); });
Par exemple, l'invocation suivante imprime le fichier spécifié à partir du serveur spécifié : 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.