Vous êtes sur la page 1sur 17

TP Dveloppement Rseau n3 : Jeu du pendu

2012 tv <tvaira@free.fr> - v.1.0

Sommaire
La couche Application 2
Rle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Choix du protocole de transport . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Principe de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

Travail demand : le jeu du pendu 4


Premire partie : laboration du protocole . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Principe du jeu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Droulement dune partie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Variantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Identification des rles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Modle rseau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Structure des messages de la couche Application . . . . . . . . . . . . . . . . . . . . . . . 6
Ct client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Ct serveur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Diagrammes des changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Tests de validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Deuxime partie : mise en oeuvre sous Qt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Le module QtNetwork . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Les classes fournies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Prsentation de la classe QTcpSocket . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Mise en oeuvre de la classe QTcpSocket . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Troisime partie : ralisation du programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

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 ...

Rappel : lapplication ct client demande un service et lapplication ct serveur rend le service.

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.

Choix du protocole de transport


Le point important pour la couche Application est le choix du protocole de transport utiliser.

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.

TP Dveloppement Rseau n3 : Jeu du pendu 2 / 17 2012 tv <tvaira@free.fr>


LA COUCHE APPLICATION

Protocole Avantages Inconvnients


TCP fiable (donnes acquittes et rmises si non re- lent car adapte le dbit des donnes envoyes
ues), permet de traiter des gros volumes de don- la bande passante disponible (contrle de flux et
nes en utilisant la segmentation de congestion), complexe mettre en oeuvre (no-
tamment le multi-clients ct serveur), utilisation
du broadcast et multicast impossible
UDP simple (pas de connexion, pas dtats entre le pas dacquittement donc pas de garantie de bon
client et le serveur), conomique en bande pas- acheminement, pas de dtection de pertes donc
sante (en-tte de 8 octets), sans contrle de conges- pas retransmission possible, pas de contrle de
tion donc UDP peut mettre sans attendre flux et donc risque de saturation des tampons (buf-
fers), pas de squencement donc les datagrammes
peuvent tre traits dans le dsordre

En rsum, TCP est considr comme able mais lent. Et inversement, UDP est rapide mais peu able.

Les applications utiliseront TCP car :


gros volume de donnes et peu sensible au dbit
besoin dun service fiable (donc pas de tolrance aux pertes)
pas besoin du multicast ni du broadcast

Les applications utiliseront UDP car :


faible volume de donnes et sensible au dbit
pas besoin dun service fiable (donc tolrance aux pertes)
besoin du multicast ou du broadcast

90% des services d'Internet utilisent TCP !

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)

Un protocole est toujours dcompos en deux parties :


le PCI (Protocol Control Information) : un en-tte (header) dcrivant le protocole
les DATA (DONNES) : une suite doctets en provenance de la couche immdiatement suprieure

Un protocole de la couche Application permet l'change de messages.

TP Dveloppement Rseau n3 : Jeu du pendu 3 / 17 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND : LE JEU DU PENDU

Travail demand : le jeu du pendu


Lobjectif est de programmer un jeu du pendu en rseau partir des sockets TCP/IP en mode connect.
Il vous faudra dfinir un protocole de couche application pour permettre un dialogue entre le client et le
serveur.
Vous travaillerez en quipe de 3 pour la dfinition du protocole et les tests. Par contre, chacun crira son
programme. Si le protocole est bien dfini et respect, les programmes pourront fonctionner correctement
au sein mme dune quipe.
Un numro de port pour le serveur sera attribu par quipe :
quipe n1
5001,
quipe n2
5002,
...

Une prsentation du protocole dni sera faite par l'quipe oralement en classe.

Premire partie : laboration du protocole


Principe du jeu

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.

Droulement dune partie

Les deux joueurs dans cet exemple sappellent A et B.


B choisit un mot et fabrique le mot dcouvrir : les lettres composant le mot sont remplaces par des
tirets sauf pour la premire et la dernire lettre.
A propose une lettre.
La lettre fait-elle partie du mot ?
Oui : B linscrit sa place autant de fois quelle se trouve dans le mot.
Non : B dessine le premier trait du pendu (un coup jou et perdu).

Le jeu se poursuit jusqu ce que :


A gagne la partie en trouvant toutes les lettres du mot ou en le devinant correctement.
A perd la partie lorsque le nombre de coups jous et perdus est gal au nombre de coups maximum
pour dcouvrir le mot.
A abandonne la partie (que fait B ? ...)

Variantes

Il existe des variantes :


Le nombre de coups maximum peut varier aussi en fonction du nombre de traits qui composent le dessin.
On peut par exemple augmenter leur nombre en dessinant pendant la partie non seulement le pendu,
mais aussi la potence, ce qui augmenterait les chances du joueur.

TP Dveloppement Rseau n3 : Jeu du pendu 4 / 17 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND : LE JEU DU PENDU

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.

Identification des rles

Dans une architecture client/serveur, il est important didentifier les rles :


Le client : celui qui demande le service .
Le serveur : celui qui offre le service .
Question 1. Quel service est rendu par le serveur ?

Rponse : Ici, le service est de jouer une partie du jeu du pendu .

Question 2. Que demande le client ?

Rponse : Le client demande jouer une partie du jeu du pendu.

Question 3. Que rpondra le serveur la demande du client ?

Rponse : Le serveur lui rpondra quil accepte (ou non) sa demande en lui proposant un
mot mystre dcouvrir en un nombre maximum de coups.

Question 4. Quest-ce qui est donc la charge du serveur ?

Rponse : Si le serveur accepte de jouer , il a la charge de choisir un mot dcouvrir et de


le proposer au client qui a mis la demande.

Question 5. Qui du serveur ou du client fixe les rgles du jeu ?

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

Question 7. Dans ce modle, que reste-t-il dfinir ?

Rponse : Le protocole de la couche Application qui implmente le service jeu du pendu .

TP Dveloppement Rseau n3 : Jeu du pendu 5 / 17 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND : LE JEU DU PENDU

Structure des messages de la couche Application

Le travail consiste laborer la structure des messages changs par le client et le serveur ainsi que
leur squencement.

Question 8. Le protocole mettre en oeuvre serat-t-il orient caractre ou orient bit ?

Rponse : Ici, il est prfrable dlaborer un protocole orient caractre.

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.

On vous fixe les contraintes suivantes dans les messages changs :


tous les champs seront changs sous la forme de caractres
toutes les informations de protocoles seront changes en MAJUSCULE
toutes les lettres et le mot seront changes en minuscule

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

TP Dveloppement Rseau n3 : Jeu du pendu 6 / 17 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND : LE JEU DU PENDU

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.

Diagrammes des changes

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.

Deuxime partie : mise en oeuvre sous Qt


Le module QtNetwork

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.

TP Dveloppement Rseau n3 : Jeu du pendu 7 / 17 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND : LE JEU DU PENDU

Les classes fournies

Qt fournit de nombreuses classes pour la programmation rseau (cf. la documentation de Qt).


En rsum, on disposera :
des classes comme QFtp pour les protocoles de la couche Application
des classes de plus bas niveau comme QTcpSocket, QTcpServer et QUdpSocket
des classes de plus haut niveau pour une gestion simplifie du rseau comme QNetworkConfiguration,
QNetworkConfigurationManager, ...

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.

Prsentation de la classe QTcpSocket

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.

TP Dveloppement Rseau n3 : Jeu du pendu 8 / 17 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND : LE JEU DU PENDU

Mise en oeuvre de la classe QTcpSocket

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).

tape n1 : cration de la socket et connexion au serveur


On commence par crer un fichier clientTCP-1.pro avec le contenu suivant :
QT += core network
TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .
HEADERS += client-1.h
SOURCES += client-1.cpp clientTCP-1.cpp
Le fichier de projet clientTCP-1.pro

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>

#define PORT_SERVEUR 5000

class Client : public QObject


{
Q_OBJECT

public:
Client( QObject *parent=0 );
~Client();
void demarrer();

private:
QTcpSocket *tcpSocket; // la socket
};

#endif
client-1.h

Dans cette premire tape, on ralisera :


1. linstanciation dun objet de la classe QTcpSocket
2. la connexion au serveur avec la mthode connectToHost()

TP Dveloppement Rseau n3 : Jeu du pendu 9 / 17 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND : LE JEU DU PENDU

Remarque : Qt fournit une classe QHostAddress pour manipuler ladresse IP dune machine.

La dfinition de la classe Client sera donc la suivante :


#include "client-1.h"

Client::Client( QObject *parent/*=0*/ ) : QObject( parent )


{
qDebug() << QString::fromUtf8("Instancie un objet QTcpSocket");
tcpSocket = new QTcpSocket(this); // 1.
qDebug() << QString::fromUtf8("tat de la socket :") << tcpSocket->state();
}

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

Il ne reste plus qu crire la fonction principale du programme de test :


#include <QApplication>

#include "client-1.h"

int main( int argc, char **argv )


{
QApplication a( argc, argv );

Client client;

client.demarrer();

return 0;
}
clientTCP-1.cpp

La procdure de test est assez simple. Il suffit de faire successivement :


$ qmake
$ make

$ ./clientTCP-1

TP Dveloppement Rseau n3 : Jeu du pendu 10 / 17 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND : LE JEU DU PENDU

"Instancie un objet QTcpSocket"


"tat de la socket :" QAbstractSocket::UnconnectedState
"Connexion au serveur"
"tat de la socket :" QAbstractSocket::ConnectingState
"Ferme la socket"

tape n2 : vrification du bon fonctionnement de la connexion


Dans cette deuxime tape, on va intgrer les fonctionnalits propres Qt en utilisant le mcanisme
signal/slot.
On commence par crer un fichier clientTCP-2.pro avec le contenu suivant :
QT += core network
TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .
HEADERS += client-2.h
SOURCES += client-2.cpp clientTCP-2.cpp
Le fichier de projet clientTCP-2.pro

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

On va donc crer les slots suivants dans la classe Client :


#ifndef CLIENT_H
#define CLIENT_H

#include <QObject>
#include <QtNetwork>
#include <QDebug>

#define PORT_SERVEUR 5000

class Client : public QObject


{
Q_OBJECT

public:
Client( QObject *parent=0 );
~Client();
void demarrer();

private:
QTcpSocket *tcpSocket;

private slots:

TP Dveloppement Rseau n3 : Jeu du pendu 11 / 17 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND : LE JEU DU PENDU

void estConnecte(); // pour le signal connected()


void estDeconnecte(); // pour le signal disconnected()
void recevoir(); // pour le signal readyRead()
void gererErreur(QAbstractSocket::SocketError erreur); // pour le signal error()
};

#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( QObject *parent/*=0*/ ) : QObject( parent )


{
qDebug() << QString::fromUtf8("Instancie un objet QTcpSocket");
tcpSocket = new QTcpSocket(this);

// La connexion des signaux aux slots


connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(recevoir()));
connect(tcpSocket, SIGNAL(connected()), this, SLOT(estConnecte()));
connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(estDeconnecte()));
connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(gererErreur(
QAbstractSocket::SocketError)));

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");
}

TP Dveloppement Rseau n3 : Jeu du pendu 12 / 17 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND : LE JEU DU PENDU

void Client::gererErreur(QAbstractSocket::SocketError erreur)


{
qDebug() << QString::fromUtf8("Une erreur sest produite sur la socket : ") << tcpSocket
->errorString();
qDebug() << QString::fromUtf8("Erreur : ") << erreur;

// Il est possible de personnaliser le traitement de lerreur


// liste des erreurs : http://doc.qt.digia.com/qt/qabstractsocket.html#SocketError-enum
/*switch(erreur)
{
case QAbstractSocket::HostNotFoundError:
// ...
break;
case QAbstractSocket::ConnectionRefusedError:
// ...
break;
case QAbstractSocket::RemoteHostClosedError:
// ...
break;
default:
// ...
}*/
}
client-2.cpp

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"

int main( int argc, char **argv )


{
QApplication a( argc, argv );

Client client;

client.demarrer();

return a.exec(); // permettra de traiter les signaux


}
clientTCP-2.cpp

On va raliser trois tests pour valider cette deuxime itration :


$ qmake
$ make

// Test n1 : il ny a pas de serveur en coute sur le port 5000


$ ./clientTCP-2
"Instancie un objet QTcpSocket"
"Connexion au serveur"

TP Dveloppement Rseau n3 : Jeu du pendu 13 / 17 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND : LE JEU DU PENDU

"Une erreur sest produite sur la socket : " "Connection refused"


"Erreur : " QAbstractSocket::ConnectionRefusedError
^C

// 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

tape n3 : change des donnes


Commencez par crer la version 3 en renommant les fichiers (.pro, .h et .cpp).
On rappelle quune communication TCP est bidirectionnelle full duplex et oriente flux doctets. Il nous
faut donc des fonctions pour crire (envoyer) et lire (recevoir) des octets dans la socket.

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.

TP Dveloppement Rseau n3 : Jeu du pendu 14 / 17 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND : LE JEU DU PENDU

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( QObject *parent/*=0*/ ) : QObject( parent )


{
qDebug() << QString::fromUtf8("Instancie un objet QTcpSocket");
tcpSocket = new QTcpSocket(this);

connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(recevoir()));


connect(tcpSocket, SIGNAL(connected()), this, SLOT(estConnecte()));
connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(estDeconnecte()));
connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(gererErreur(
QAbstractSocket::SocketError)));

Client::~Client()
{
qDebug() << QString::fromUtf8("Ferme la socket");
tcpSocket->close();
}

void Client::demarrer()
{
// Par prcaution, on dsactive les connexions prcdentes
tcpSocket->abort();

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");

qDebug() << QString::fromUtf8("Adresse IP du client : ") + tcpSocket->localAddress().


toString();
qDebug() << QString::fromUtf8("Numro de port du client : ") + QString::number(tcpSocket
->localPort());
qDebug() << QString::fromUtf8("Adresse IP du serveur : ") + tcpSocket->peerAddress().
toString();
qDebug() << QString::fromUtf8("Numro de port du serveur : ") + QString::number(tcpSocket
->peerPort());

QByteArray message("Hello world !\n"); // reprsente le message de la couche Application


qint64 ecrits = -1;

// Envoie du message
ecrits = tcpSocket->write(message);
switch(ecrits)

TP Dveloppement Rseau n3 : Jeu du pendu 15 / 17 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND : LE JEU DU PENDU

{
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();

qDebug() << QString::fromUtf8("Des donnes ont t reues en provenance du serveur");


qDebug() << QString::fromUtf8("Octets reus : ") << message.size();
qDebug() << QString::fromUtf8("Message reu du serveur : ") << message;
}

void Client::gererErreur(QAbstractSocket::SocketError erreur)


{
qDebug() << QString::fromUtf8("Une erreur sest produite sur la socket : ") << tcpSocket
->errorString();
qDebug() << QString::fromUtf8("Erreur : ") << erreur;

// Il est possible de personnaliser le traitement de lerreur


// liste des erreurs : http://doc.qt.digia.com/qt/qabstractsocket.html#SocketError-enum
/*switch(erreur)
{
case QAbstractSocket::HostNotFoundError:
// ...
break;
case QAbstractSocket::ConnectionRefusedError:
// ...
break;
case QAbstractSocket::RemoteHostClosedError:
// ...
break;
default:
// ...
}*/
}
client-3.cpp

TP Dveloppement Rseau n3 : Jeu du pendu 16 / 17 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND : LE JEU DU PENDU

On termine par un test de validation :


$ qmake
$ make

// on utilise en parallle un serveur netcat sur le port 5000 :


$ ./clientTCP-3
"Instancie un objet QTcpSocket"
"Connexion au serveur"
"Socket connecte au serveur"
"Adresse IP du client : 127.0.0.1"
"Numro de port du client : 39059"
"Adresse IP du serveur : 127.0.0.1"
"Numro de port du serveur : 5000"
"Message envoy : " "Hello world !
"
"Octets envoys : " 14
"Message envoy avec succs !"
"Des donnes ont t reues en provenance du serveur"
"Octets reus : " 3
"Message reu du serveur : " "ok
"
^C

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)

Troisime partie : ralisation du programme


Question 14. crire les programmes demands. Une version graphique du client peut tre ralis.

TP Dveloppement Rseau n3 : Jeu du pendu 17 / 17 2012 tv <tvaira@free.fr>