Client FTP SCXML
Implémente un client FTP simple à l'aide d'une machine à états.
Le client FTP utilise la méthode « Qt SCXML » pour implémenter un client FTP capable de communiquer avec un service FTP en envoyant des messages de contrôle FTP traduits à partir d'événements de la machine à états et en traduisant les réponses du serveur en événements de la machine à états. Les données reçues du serveur FTP sont affichées sur la console.
La norme RFC 959 spécifie des diagrammes d'états pour la gestion des commandes du client FTP. Ceux-ci peuvent être facilement convertis en SCXML afin de tirer parti des états imbriqués de ce langage. Les connexions entre le client et le serveur ainsi que le transfert de données sont implémentés à l'aide de C++. De plus, les signaux et slots 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 l'échec.
- W pour « en attente d'une réponse ».
- P pour fournir un mot de passe à la demande du serveur.
La machine à états est définie dans le fichier simpleftp.scxml et compilée en une classe ` FtpClient ` qui implémente 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. De plus, nous implémentons une classe ` FtpControlChannel ` et une classe ` FtpDataChannel ` qui gèrent les sockets TCP et les serveurs, et convertissent les fins de ligne.
Exécution de l'exemple
Vous pouvez exécuter l'exemple à partir de :
- Qt Creator
Ouvrez le mode « Welcome » et sélectionnez l'exemple dans « Examples ». Pour plus d'informations, consultez Qt Creator: Tutoriel : Compiler et exécuter.
- Qt Extension for Visual Studio Code
Exécutez la commande « Qt: Open Qt examples » à partir de Command Palette, puis sélectionnez l'exemple dans la liste. Pour plus d'informations, consultez Qt Extension for Visual Studio Code: Tutoriel : Compiler et exécuter.
Compilation de la machine à états
Nous effectuons la liaison avec le module Qt SCXML en ajoutant la ligne suivante aux fichiers de compilation du projet.
Avec qmake, nous ajoutons ce qui suit au fichier ftpclient.pro
QT = core scxml networkNous spécifions ensuite la machine à états à compiler :
STATECHARTS += simpleftp.scxmlAvec 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 à états à compiler :
qt6_add_statecharts(ftpclient
simpleftp.scxml
)Le compilateur Qt SCXML, qscxmlc, est lancé automatiquement pour générer les fichiers simpleftp.h et simpleftp.cpp, puis les ajouter au projet en tant que fichiers d'en-tête et de source.
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;
...Communication avec un serveur FTP
Nous affichons toutes les données récupérées depuis le 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 à états :
QObject::connect(&controlChannel, &FtpControlChannel::reply, &ftpClient,
[&ftpClient](int code, const QString ¶meters) {
ftpClient.submitEvent(QString("reply.%1xx")
.arg(code / 100), parameters);
});Nous convertissons les commandes de la machine à états 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 indiquer 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 précisons que le client FTP doit envoyer la commande suivante lorsqu’il passe à 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 précisons que le client FTP doit envoyer une chaîne vide en guise de 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 deuxième 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’appel suivant affiche 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.