Académique Documents
Professionnel Documents
Culture Documents
Sommaire
La couche Application 2
Rle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Choix du protocole de transport . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Principe de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Lobjectif est de programmer un jeu du pendu en rseau partir des sockets TCP/IP en
mode connect.
1
LA COUCHE APPLICATION
La couche Application
Rle
Cette couche est linterface entre lapplication utilisateur et le rseau. Elle va apporter luti-
lisateur les services de base offerts via le rseau, comme par exemple le transfert de fichier, la messagerie ...
Les protocoles de la couche Application sont souvent orients caractres pour des raisons de reprsentation
des donnes changer. Les protocoles orients caractres sont les plus simples mettre en oeuvre car ils ne
ncessitent pas de protocoles supplmentaires pour la reprsentation des donnes dans des formats incompatibles
(cf. little endian vs big endian, int vs oat, ...).
Cette couche contient donc tous les protocoles de haut niveau, comme par exemple Telnet, TFTP (Trivial
File Transfer Protocol), SMTP (Simple Mail Transfer Protocol), HTTP (HyperText Transfer Protocol),
FTP (File Transfer Protocol) ...
Il est videmment aussi possible dimplmenter ses propres protocoles en fonction des ses besoins et
services.
Rappel : TCP permet une communication en mode connect et UDP en mode non connect.
Par exemple, TFTP (surtout utilis sur rseaux locaux) utilisera UDP, car on part du principe que les
liaisons physiques sont suffisamment fiables et les temps de transmission suffisamment courts pour quil
ny ait pas dinversion de paquets larrive. Ce choix rend TFTP plus rapide que le protocole FTP qui
utilise TCP. A linverse, SMTP utilise TCP, car pour la remise du courrier lectronique, on veut que
tous les messages parviennent intgralement et sans erreurs.
En rsum, TCP est considr comme able mais lent. Et inversement, UDP est rapide mais peu able.
Principe de base
Rappel : Un protocole rend possible le dialogue entre des processus diffrents au sein dun rseau.
De manire gnrale, un protocole de communication dfinit lensemble des procdures (ou rgles) pour
raliser une communication :
Le dictionnaire : les primitives (demande connexion, acquittement, ...)
Le scnario du dialogue : enchanement des primitives (diagramme de lchange)
Les modalits : taille et reprsentation des informations, temps dattente, etc ...
Les messages changs : les diffrents champs (taille et contenu)
Une prsentation du protocole dni sera faite par l'quipe oralement en classe.
Le pendu est un jeu consistant trouver un mot en devinant quelles sont les lettres qui le composent. Le
jeu se joue traditionnellement deux. On a un nombre maximum de tentatives (qui correspondent au
dessin du pendu ) pour dcouvrir ce mot mystre.
Variantes
Il serait possible denvisager que le joueur propose aussi la position de la lettre ce qui augmenterait la
difficult du jeu. Ou quil ait un temps limite pour dcouvrir le mot masqu ...
Dans ces variantes, il apparat la possibilit dintgrer un niveau de difficult pour ce jeu (de dbutant
expert par exemple). Le choix des mots dcouvrir peut aussi tre li au niveau de la partie. Dautre
part, on pourrait instaurer des choix de mots suivant des thmes.
videmment, tout ceci influencera llaboration dun protocole.
Rponse : Le serveur lui rpondra quil accepte (ou non) sa demande en lui proposant un
mot mystre dcouvrir en un nombre maximum de coups.
Rponse : Cest le serveur qui fixe les rgles du jeu en dterminant et contrlant par
exemple le nombre de coups maximum pour le dcouvrir.
Modle rseau
Ici, le choix se porte sur le modle DoD pour faire fonctionner ce jeu en TCP/IP.
Question 6. Complter le modle DoD ci-dessous en chosissant notamment un protocole de transport ?
Couche Protocole
Application
Transport
Rseau
Interface
Le travail consiste laborer la structure des messages changs par le client et le serveur ainsi que
leur squencement.
On conservera les dlimiteurs utiliss par les autres protocoles connus de la couche Application (HTTP,
FTP, ...) : l'espace comme sparateur de champ et "\r\n" comme dlimiteur de n de message.
videmment, on distinguera les messages envoys par le client de ceux envoys par le serveur.
Le PCI d'un message pourra avoir une longueur xe car c'est plus plus simple grer.
Ct client
Dans le message quil envoie au serveur, le client doit prciser le type de sa requte (ou si vous prfrez
de sa demande). Le client peut par exemple :
demander jouer une nouvelle partie
proposer une lettre ou un mot
abandonner la partie en cours
...
Question 9. Dfinissez prcisment la structure et les champs dun message envoy par le client.
N'oubliez pas d'indiquer les valeurs attendues et valides des dirents champs composant un message.
Ct serveur
Par principe, le serveur reoit toujours des requtes (ou si vous prfrez des demandes) en provenance du
client.
Il est plus prudent de considrer que le serveur peut recevoir des demandes valides ou invalides. Le
serveur rpondra donc toujours en prcisant un code rponse.
Les codes rponses seront formats sur trois caractres (xxx) dont les significations sont :
Le premier chiffre indique le statut de la rponse (1 pour succs ou 2 pour chec)
Le second chiffre et le troisime chiffre prcise un code derreur (00 99) ou 00 en cas de succs
Si le serveur rpond avec succs une demande du client, il renverra toujours un code rponse 1xx sinon
il renverra un code erreur compris entre 200 299.
Le code rponse permettra aussi de grer ltat de la partie au final. On peut fixer par exemple les code
suivants :
101 : partie gagne par le client (le mot a t dcouvert en un nombre de coups infrieur au maximum
fix)
102 : partie perdue par le client (le mot na pas t dcouvert et un nombre maximum de coups a t
atteint)
103 : partie abandonne par le client (est-ce que le mot doit tre dvoil ?)
Question 10. Dfinissez prcisment les codes erreurs renvoys par le serveur.
Question 11. Dfinissez maintenant la structure et les champs dun message envoy par le serveur.
N'oubliez pas d'indiquer les valeurs attendues et valides des dirents champs composant un message.
Question 12. Dfinissez prcisment les diagrammes qui dcrivent : une partie gagne, perdue, aban-
donne par le client.
Tests de validation
Question 13. En utilisant les outils netcat et telnet, procder aux tests de validation du protocole
dfini par lquipe.
Puis faire valider son protocole par votre enseignant lors d'une runion d'quipe.
Le module QtNetwork offre des classes qui vous permettent dcrire vos propres clients et serveurs
TCP/IP.
Pour inclure les dclarations des classes de ce module, il vous faut utiliser la directive suivante :
#include <QtNetwork>
Pour disposer ce module, il vous faut ajouter cette ligne votre fichier de projet .pro :
QT += network
N'oubliez pas de refaire un qmake lorsque vous modier un chier de projet .pro.
Ici, on aura juste besoin des classes de base pour limplmentation des sockets sous Qt soit :
La classe QTcpSocket fournit une interface pour le protocole TCP. On peut donc utiliser QTcpSocket
pour implmenter des protocoles rseau standard comme POP et SMTP, aussi bien que des protocoles
personnaliss.
Rappel : la programmation Qt est base sur le mcanisme des signaux et des slots.
La classe QTcpSocket est asynchrone et met des signaux pour reporter des changements de statuts et des
erreurs. Elle repose sur une boucle dvnements pour dtecter des donnes arrivantes et automatiquement
envoyer les donnes partantes.
Les signaux quil faut au minimum grer par connect() ct client :
readyRead() signale que des donnes ont t reues et sont prtes tre lues
connected() signale que la socket est dans ltat connect
disconnected() signale que la socket est dans ltat dconnect
error() signale quune erreur sest produite sur la socket
Vous pouvez crire des donnes dans le socket avec QTcpSocket::write() et en lire avec QTcpSocket::read().
QTcpSocket possde deux ux indpendants de donnes : un pour crire et l'autre pour lire.
Puisque QTcpSocket hrite de QIODevice, vous pouvez lutiliser avec QTextStream et QDataStream pour
grer vos donnes.
En lisant depuis un QTcpSocket, vous devez tre sr quassez de donnes sont disponibles en appelant
QTcpSocket::bytesAvailable() avant.
On appellera la mthode non bloquante QTcpSocket::connectToHost() pour se connecter un serveur.
Une connexion TCP doit tre tablie vers un hte distant et un port avant que le transfert de donnes
puisse commencer. Une fois la connexion tablie, ladresse IP et le port du point de communication
distant sont disponibles avec les fonctions QTcpSocket::peerAddress() et QTcpSocket::peerPort().
nimporte quel moment, le point de communication distant peut fermer la connexion et le transfert de
donnes sarrtera immdiatement.
Pour la mise en oeuvre de la programmation socket sous Qt, on va partir sur un exemple construit par
itrations sans utiliser de composants graphiques.
Remarque : un dveloppement itratif sorganise en une srie de dveloppement trs courts de dure fixe
nomme itrations. Le rsultat de chaque itration est un systme partiel excutable, test et intgr (mais
incomplet).
Lexemple est bas sur la cration dune classe Client. Pour bnficier des fonctionnalits Qt, la classe
Client hritera de la classe de base QObject et intgrera la macro Q_OBJECT pour bnficier du mcanisme
signal/slot.
#ifndef CLIENT_H
#define CLIENT_H
#include <QObject>
#include <QtNetwork>
#include <QDebug>
public:
Client( QObject *parent=0 );
~Client();
void demarrer();
private:
QTcpSocket *tcpSocket; // la socket
};
#endif
client-1.h
Remarque : Qt fournit une classe QHostAddress pour manipuler ladresse IP dune machine.
Client::~Client()
{
qDebug() << QString::fromUtf8("Ferme la socket");
tcpSocket->close();
}
void Client::demarrer()
{
qDebug() << QString::fromUtf8("Connexion au serveur");
//tcpSocket->connectToHost(QHostAddress((QString)"0.0.0.0"), PORT_SERVEUR); // remplacer
0.0.0.0 par ladresse IP du serveur
tcpSocket->connectToHost(QHostAddress::LocalHost, PORT_SERVEUR); // 2. (ici le serveur
sera localhost)
qDebug() << QString::fromUtf8("tat de la socket :") << tcpSocket->state();
}
client-1.cpp
#include "client-1.h"
Client client;
client.demarrer();
return 0;
}
clientTCP-1.cpp
$ ./clientTCP-1
Rappel : La classe QTcpSocket est asynchrone et met des signaux pour reporter des changements de
statuts et des erreurs. Elle repose sur une boucle dvnements pour dtecter des donnes arrivantes et
automatiquement envoyer les donnes partantes.
Les signaux quil faudra au minimum grer ct client sont :
readyRead() signale que des donnes ont t reues et sont prtes tre lues
connected() signale que la socket est dans ltat connect
disconnected() signale que la socket est dans ltat dconnect
error() signale quune erreur sest produite sur la socket
#include <QObject>
#include <QtNetwork>
#include <QDebug>
public:
Client( QObject *parent=0 );
~Client();
void demarrer();
private:
QTcpSocket *tcpSocket;
private slots:
#endif
client-2.h
La dfinition de la classe Client sera donc la suivante en intgrant la connexion des slots avec connect() :
#include "client-2.h"
Client::~Client()
{
qDebug() << QString::fromUtf8("Ferme la socket");
tcpSocket->close();
}
void Client::demarrer()
{
qDebug() << QString::fromUtf8("Connexion au serveur");
//tcpSocket->connectToHost(QHostAddress((QString)"0.0.0.0"), PORT_SERVEUR);
tcpSocket->connectToHost(QHostAddress::LocalHost, PORT_SERVEUR);
}
void Client::estConnecte()
{
qDebug() << QString::fromUtf8("Socket connecte au serveur");
}
void Client::estDeconnecte()
{
qDebug() << QString::fromUtf8("Socket dconnecte au serveur");
}
void Client::recevoir()
{
qDebug() << QString::fromUtf8("Des donnes ont t reues en provenance du serveur");
}
Il ne reste plus qu modifier la fonction principale du programme de test pour lui demander de boucler
sur la gestions des vnements en appelant a.exec() :
#include <QApplication>
#include "client-2.h"
Client client;
client.demarrer();
// Test n2 : il y a un serveur (netcat) en coute sur le port 5000 et celui envoie des
donnes
$ ./clientTCP-2
"Instancie un objet QTcpSocket"
"Connexion au serveur"
"Socket connecte au serveur"
"Des donnes ont t reues en provenance du serveur"
^C
// Test n3 : il y a un serveur (netcat) en coute sur le port 5000 mais celui-ci ferme la
connexion
$ ./clientTCP-2
"Instancie un objet QTcpSocket"
"Connexion au serveur"
"Socket connecte au serveur"
"Une erreur sest produite sur la socket : " "The remote host closed the connection"
"Erreur : " QAbstractSocket::RemoteHostClosedError
"Socket dconnecte au serveur"
^C
Normalement les octets envoys ou reus respectent un protocole de couche APPLICATION. Ici, pour
les tests, notre couche APPLICATION sera vide ! C'est--dire que les donnes envoyes et reues ne
respecteront aucun protocole et ce seront de simples caractres ASCII.
Vous pouvez crire des donnes dans le socket avec QTcpSocket::write() et en lire avec QTcpSocket::read()
ou QTcpSocket::readAll().
Faire communiquer deux processus sans aucun protocole de couche APPLICATION est tout de mme
difficile ! On va simplement fixer les rgles dchange suivantes :
le client envoie en premier une chane de caractres une fois connecte
et le serveur lui rpondra "ok"
Ici, on va simplement utiliser le type QByteArray pour lchange des donnes. Si vous implmentez
un protocole personnalis pour la couche Application, vous pouvez utiliser aussi QTextStream ou
QDataStream pour grer vos donnes changes.
La dfinition de la classe Client sera donc la suivante en intgrant une amlioration (affichage des
informations sur les points de communication local et distant) et deux ajouts (lmission et la rception
de donnes) :
#include "client-3.h"
Client::~Client()
{
qDebug() << QString::fromUtf8("Ferme la socket");
tcpSocket->close();
}
void Client::demarrer()
{
// Par prcaution, on dsactive les connexions prcdentes
tcpSocket->abort();
void Client::estConnecte()
{
qDebug() << QString::fromUtf8("Socket connecte au serveur");
// Envoie du message
ecrits = tcpSocket->write(message);
switch(ecrits)
{
case -1 : /* une erreur ! */
qDebug() << QString::fromUtf8("Erreur lors de lenvoi !"); break;
default: /* envoi de n octets */
qDebug() << QString::fromUtf8("Message envoy : ") << message;
qDebug() << QString::fromUtf8("Octets envoys : ") << ecrits;
qDebug() << QString::fromUtf8("Message envoy avec succs !");
}
}
void Client::estDeconnecte()
{
qDebug() << QString::fromUtf8("Socket dconnecte au serveur");
}
void Client::recevoir()
{
QByteArray message;
if (tcpSocket->bytesAvailable() < 0)
return;
message = tcpSocket->readAll();
Pour aller plus loin sur la programmation rseau sous Qt, il vous faudra consulter la documentation
officielle :
Le module network (doc.qt.digia.com/qt/qtnetwork.html et (qt.developpez.com/doc/4.7/programmation-
reseau/)
La classe QTcpSocket (doc.qt.digia.com/qt/qtcpsocket.html)
La classe QAbstractSocket (doc.qt.digia.com/qt/qabstractsocket.html)
La classe QIODevice (doc.qt.digia.com/qt/qiodevice.html)
La classe QByteArray (doc.qt.digia.com/qt/qbytearray.html)
La classe QDataStream (doc.qt.digia.com/qt/qdatastream.html)
La classe QTextStream (doc.qt.digia.com/qt/qtextstream.html)
On peut conseiller de regarder les exemples fournis par Qt (et principalement pour commencer le
client/serveur Fortune) :
Tous les exemples (doc.qt.digia.com/qt/examples-network.html)
Le client Fortune (doc.qt.digia.com/qt/network-fortuneclient.html)
Le serveur Fortune (doc.qt.digia.com/qt/network-fortuneserver.html)