S.T.S. Système Numérique Informatique et Réseaux Travaux Pratique programmation réseau avec QT4 1. OBJECTIF Utilisation des sockets avec la bibliothèque QT4 Mettre en pratique les sockets en mode événementiel. Utiliser cette propriété pour réaliser un serveur multi-clients. Points techniques abordés : Codage de l information Programmation sockets avec QT4. Communication réseau 2. CONDITIONS DE RÉALISATION Travail individuel sur micro-ordinateurs avec QT Creator Un serveur et un client sont disponibles pour la mise au point. Compte rendu et code à rendre. 3. RESSOURCES Les classes «socket» dans la technologie QT, consulter le site http://doc.qt.nokia.com/4.7/qtnetwork.html et plus particulièrement les classes, QTcpSocket, QTcpServeur. 4. LE BESOIN Les distributeurs automatiques de billets (DAB) permettent de se connecter à la banque. Ils offrent la possibilité d interroger un compte pour en connaître le solde, de déposer de l argent et d en retirer. C'est ces fonctionnalités que nous allons étudier dans un premier temps côté client (sur le DAB) puis côté serveur (à la banque).
5. BANQUE ~ CÔTÉ CLIENT 5.1. Création du projet Créez le projet ClientBanque de type Application graphique en C++ sous QT4 avec QT Creator. La classe principale ce nomme DAB_MainWindow elle hérite de QMainWindow comme le montre le diagramme de classes partiel ci-dessous. C est la seule classe ou vous aurez à intervenir. QMainWindow QIODevice QAbstractSocket DAB_MainWindow SocketC lientbanque 1 1 QTcpSocket De même, ajoutez l attribut réalisant la liaison avec la classe QTcpSocket. 5.2. Création de l'ihm L interface du client aura l aspect suivant : Nommez chaque Widget de manière à ce qu il conserve son type de Widget et le nom auquel il se rapporte, exemple : listwidgetetat Tant que la connexion avec la banque n est pas établie, les opérations vers la banque ne sont pas possibles (les boutons sont désactivés), la zone d édition pour les messages de la banque est en lecture seule. Le listwidget contenant l état de la connexion avec la banque indique les différents états de la connexion et les messages d erreur système. Le bouton Connexion devient Déconnexion lorsque la connexion est établie. STS SNir - LPo Touchard-Washington Le Mans page 2
Fonctionnalités attendues du distributeur automatique de billets : Mise sous tension Attente client Connexion Deconnexion Deconnexion Connecté à la banque Numéro de compte reconnu Numéro de compte inconnu Envoi [Solde] Mise en relation avec le compte Envoi [Dépot] Envoi [Retrait] Comme l indique le diagramme à états ci-dessus, c est seulement lorsque le client est connecté à la banque et que son numéro de compte est reconnu que les opérations vers la banque peuvent être réalisées (par sécurité, les opérations sont désactivées sur l'ihm). La déconnexion reste possible à chaque état. 5.3. Utilisation de la classe QTcpSocket Après l'initialisation de l attribut représentant le lien entre les classes DAB_MainWindow et QTcpSocket, reliez les signaux en provenance du socket client, la connexion au serveur, sa déconnexion et la présence de données à lire à des slots chargés du traitement correspondant dans la classe gérant l'ihm. Chaque connexion entre signaux et slots doit faire l objet d un test avec l apparition d une boîte de message indiquant l erreur et fermant l application. L état de la connexion avec le serveur de la banque est reporté dans le listwidget prévu à cet effet. Réalisez le code nécessaire pour l envoi du numéro de compte vers la banque le numéro est transmis s il est supérieur à 0. La trame à transmettre se décompose ainsi : Taille des données Commande Valeur De type quint16 Le caractère 'N' sous la forme d un Qchar Un entier (type int) Réalisez le code nécessaire pour recevoir la réponse de la banque et l afficher dans la zone d édition prévue à cet effet. Taille des données De type quint16 Commande Une chaîne de caractère sous la forme d une QString. STS SNir - LPo Touchard-Washington Le Mans page 3
Opérations vers la banque : Lors de l affichage de l'ihm du distributeur, on souhaite que le Bouton radio Solde soit coché par défaut. Réalisez le code nécessaire dans la méthode qui vous semble la plus appropriée. L appui sur le bouton Envoi doit envoyer à travers le socket le type d opération souhaité, suivi éventuellement du montant de la transaction suivant le format de trame : Taille des données Opération Montant De type quint16 Le caractère 'R' sous la forme d un Qchar Un réel (type float) De type quint16 Le caractère 'D' sous la forme d un Qchar Un réel (type float) De type quint16 Le caractère 'S' sous la forme d un Qchar Sans objet Pour la réponse de la banque si tout va bien vous n avez rien à faire 6. BANQUE ~ CÔTÉ SERVEUR Que se passe t'il lorsqu une deuxième instance du client essaye de se connecter au serveur. Les opérations sont-elles possibles simultanément sur deux comptes différents? 6.1. Création du projet Créez le projet ServeurBanque de type Application graphique en C++ sous QT4 avec QT Creator. La classe principale se nomme BanqueMainWindow elle hérite de QMainWindow comme le montre le diagramme de classes partiel ci-dessous. QIODevice QTcpServer QAbstractSocket QMainWindow QTcpSocket BanqueMainWindow 1 leserveur 1 ServeurBanque ServeurBanque () ~ServeurBanque() Start() Stop() Envoye rmessage() slotne wconnection() slotclientdisconnected() slotreadyread() lesconnexionclients * CompteClient num Com pte : integer solde : float Deposer() Retirer() O btenirsolde() DefinirNum Com pte() O btenirnum Com pte() Com pteclient() L IHM de la banque comporte juste un bouton Quitter qui ferme l application. Réalisez ce traitement. STS SNir - LPo Touchard-Washington Le Mans page 4
Réalisation de la classe ServeurBanque (1 ère Partie) : Pour la gestion du serveur de la banque, on propose la classe ServeurBanque qui hérite de la classe QTcpServer comme le montre le diagramme de classes. Le constructeur de la classe ServeurBanque prend comme paramètre d entrée un pointeur sur un QObject par défaut initialisé à 0 qui sera transmis au constructeur de la classe de base. Il initialise également la liaison entre le signal indiquant la présence de la connexion d un nouveau client au slot correspondant. En cas d erreur une boîte de message apparaît signalant que la liaison n a pu avoir lieu. La méthode ServeurBanque::Start() lance si cela est possible, l écoute du socket sur toutes les interfaces réseaux de l ordinateur sur le port 8888. Si l écoute n est pas possible, une boîte de message signale l erreur et ferme le socket Serveur. Après avoir initialisé l attribut leserveur dans la classe BanqueMainWindow comme le préconise le diagramme de classes, la méthode est ServeurBanque::Start() appelée. Pour la testé, lancez une première fois l application, elle se lance, relancez la une deuxième fois la boîte indiquant l erreur de l écoute du socket doit apparaître. La méthode ServeurBanque::Stop() est chargé de fermé le socket serveur. De même pour le destructeur. Réalisation de la classe CompteClient : Déclarer la classe CompteClient comme le montre le diagramme de classes. Le constructeur de la classe CompteClient prend comme paramètre d entrée un pointeur sur un QObject par défaut initialisé à 0 qui sera transmis au constructeur de la classe de base. La méthode CompteClient ::DefinirNumCompte prend un entier en paramètre d entrée qui initialise l attribut numcompte et fixe le solde à 200 euros. La méthode CompteClient ::Deposer prend un réel en entrée et ajoute sa valeur au solde du client. La méthode CompteClient ::Retirer prend un réel en entrée si cela est possible la valeur est retranchée et la méthode retourne vrai. Sinon le paramètre de retour prend la valeur faux, la banque n accepte pas de découvert. La méthode CompteClient ::ObtenirSolde retourne la valeur du solde du compte du client. Enfin, la méthode CompteClient ::ObtenirNumCompte retourne le numéro du compte client. STS SNir - LPo Touchard-Washington Le Mans page 5
Suite de la classe ServeurBanque : Le slot ServeurBanque::SlotNewConnection a pour objectif d accepter les différents sockets client qui tentent de se connecter au serveur. L algorithme de haut niveau ci-dessous présente le traitement à effectuer hors-mis les traitements d erreurs qui devront être ajoutés. Tant qu il y a des connexions en attente client la connexion du client suivant Association des signaux indiquant des données à lire et la déconnexion en provenance du client aux deux autres slots de la classe ServeurBanque. Ajout du client dans la QList représentant les connexions des différents clients. Envoi d un message au client lui demandant son numéro de compte. Fin tantque. Réalisez le code de la méthode ServeurBanque::EnvoyezMessage. Comme son nom l'indique, elle est chargée d'envoyer un message sous la forme d'un QString passé en paramètre au client dont le pointeur est également passé en paramètre. Le code du slot ServeurBanque::slotClientDisconnected est donné ci-après, void ServeurBanque::slotClientDisconnected() { CompteClient *client = (CompteClient *)sender(); } if (!client) { QMessageBox messagebox; messagebox.settext("erreur slotclientdisconnected"); messagebox.exec(); } else { lesconnexionclients.removeone(client); client->deletelater(); } La méthode QObject::sender retourne le pointeur sur l objet qui à envoyer le signal. La méthode QList::removeOne suprime l objet passé en paramètre de la liste. À partir du code précédent réaliser le slot ServeurBanque::slotReadyRead qui réagit lorsque des données sont à lire en provenance d un client. Il est dans un premier temps nécessaire de rechercher de quel client il s agit. Vous vous attacherez ici à répondre aux besoins du client décrit dans la première partie. Comme Bonus, réalisez le code nécessaire pour qu un client retrouve le solde qu il a laissé lors de sa dernière connexion (voir QFile, QDir...). STS SNir - LPo Touchard-Washington Le Mans page 6