Académique Documents
Professionnel Documents
Culture Documents
Philippe Latu
philippe.latu(at)inetdoc.net
http://www.inetdoc.net
Rsum
Ce support est la suite de l'initiation au dveloppement en Langage C sur les sockets. L'objectif
est nouveau le mme ; utiliser un code minimaliste accessible aux dbutants. Les bibliothques
Qt prsentent un grand intrt lorsque l'on souhaite produire du code indpendant du systme
d'exploitation sous-jacent. On aborde aussi la programmation oriente objet avec ces bibliothques.
1.Copyright et Licence
Copyright (c) 2000,2015 Philippe Latu.
Permission is granted to copy, distribute and/or modify this document under the
terms of the GNU Free Documentation License, Version 1.3 or any later version
published by the Free Software Foundation; with no Invariant Sections, no
Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included
in the section entitled "GNU Free Documentation License".
Copyright (c) 2000,2015 Philippe Latu.
Permission est accorde de copier, distribuer et/ou modifier ce document selon
les termes de la Licence de Documentation Libre GNU (GNU Free Documentation
License), version 1.3 ou toute version ultrieure publie par la Free Software
Foundation ; sans Sections Invariables ; sans Texte de Premire de Couverture,
et sans Texte de Quatrime de Couverture. Une copie de la prsente Licence est
incluse dans la section intitule Licence de Documentation Libre GNU .
1.1.Meta-information
Cet article est crit avec DocBook XML sur un systme Debian GNU/Linux. Il est disponible en version
imprimable au format PDF : socket-qt.pdf.
2.Contexte de dveloppement
Comme ce support est la suite de celui sur le Langage C, on reprend le mme dcoupage en deux
programmes distincts : un serveur et un client qui changent des chanes de caractres. la diffrence
du support prcdent, on ne prsente pas le code des deux programmes. Dans le but de limiter le
volume du document, on introduit uniquement le code de la partie serveur qui reoit le message, le
traite et le rexpdie au client. Pour les tests, on peut trs bien rutiliser le programme client dj
dvelopp en Langage C : Code du programme udp-client.c
Le principe d'illustration des communications rseau reste le mme : le client ou talker met un
message que le serveur ou listener traite et retransmet vers le client. Le traitement est toujours aussi
minimaliste ; le serveur convertit la chane de caractres en majuscules.
2.1.Bibliothques Qt
Le diagramme ci-dessous prsente l'architecture des bibliothques Qt. Il met en vidence
l'indpendance entre les dveloppements et les systmes d'exploitation cibles.
Dans notre contexte, on utilise le Langage C++ et l'environnement de dveloppement intgr QtCreator.
Cet environnement comprend les bibliothques Qt rseau dont nous avons besoin.
On se propose de dvelopper le programme serveur en deux temps.
Une version sans graphisme mettant en vidence les appels de bibliothques propres l'utilisation
des sockets.
Une version avec une fentre graphique dans laquelle on afche les messages reus depuis un
programme client ainsi que l'adresse IP et le numro de port utiliss par ce programme client.
2.2.Instructions d'excution
On excute le programme client dj dvelopp en Langage C dans un Shell alors que le programme
serveur est gr directement par l'environnement QtCreator. On peut excuter ces deux programmes
sur le mme hte en utilisant l'interface de boucle locale pour les communications rseau.
Note
Dplacer le pointeur de la souris sur l'image, clicker sur le bouton droit et lancer Afcher
l'image pour lire les messages.
C'est dans la partie infrieure droite de la copie d'cran que l'on retrouve en rouge les messages
changs entre les programmes client et serveur. Le code utilis ici correspond la version sans
graphisme du programme serveur.
Le programme client, udp-talker.o
$ ./udp-talker.o
Entrez le nom du serveur ou son adresse IP :
127.0.0.1
Entrez le numro de port du serveur :
8888
Entrez quelques caractres au clavier.
Le serveur les modifiera et les renverra.
Pour sortir, entrez une ligne avec le caractre '.' uniquement.
Si une ligne dpasse 100 caractres,
seuls les 100 premiers caractres seront utiliss.
Saisie du message :
texte de test avec tabulation et espaces
Message trait : TEXTE DE TEST AVEC TABULATION ET ESPACES
Saisie du message :
_exit_
Message trait : _EXIT_
Saisie du message :
serveur arrt
Pas de rponse dans la seconde.
Saisie du message :
.
Lorsque le programme serveur est en cours d'excution, il est possible de visualiser la correspondance
entre le processus en cours d'excution et le numro de port en coute l'aide de la commande netstat.
$ netstat -aup | grep -e Proto -e 8888
(Tous les processus ne peuvent tre identifis, les infos sur les processus
non possds ne seront pas affiches, vous devez tre root pour les voir toutes.)
Proto Recv-Q Send-Q Adresse locale
Adresse distante Etat PID/Program name
udp
0
0 *:8888
*:*
3321/QtCreator_UDP
Dans l'exemple ci-dessus, le numro de port 8888 apparat dans la colonne Adresse locale et processus
numro 3321 correspond bien au programme QtCreator_UDP_receiver dans la colonne PID/Program
name.
2.3.Bibliothques utilises
Les bibliothques standards du Langage C utilises par le programme client sont prsentes dans le
document Initiation au dveloppement C sur les sockets. On ne s'intresse ici qu' l'utilisation de la
brique rseau des bibliothques Qt.
bind
Cette mthode de la classe QUdpSocket assure la liaison d'un socket avec les adresses et le numro
de port spcis.
waitForReadyRead
C'est une fonction bloquante qui attend que de nouvelles donnes soient disponibles en lecture et
que le signal readyRead() ait t mis. Le blocage expire aprs msecs millisecondes. La valeur par
dfaut est 30000 millisecondes.
La fonction retourne la valeur boolenne vrai si le signal readyRead() est mis.
readDatagram
Cette fonction assure la rception d'un datagramme de taille infrieure maxSize octets et le stocke
dans le tableau data. L'adresse et le numro de port de l'metteur sont stockes dans les pointeurs
*address et *port ( moins que les pointeurs aient une valeur nulle).
Si maxSize est trop petit, le reste du datagramme est perdu. Pour viter les pertes de donnes, on fait
appel pendingDatagramSize() pour dterminer la taille du datagramme en attente avant d'essayer
de le lire. Si maxSize vaut 0, le datagramme sera limin.
writeDatagram
Cette fonction assure l'mission d'un datagramme de taille size destination de l'adresse address
et du port port. Elle renvoie le nombre d'octets mis avec succs ou -1 en cas d'erreur.
Les datagrammes sont toujours crits en un bloc. La taille maximum d'un datagramme dpend
beaucoup du systme utilis. Elle peut atteindre 8192 octets. Si le datagramme est trop grand,
la fonction renvoie -1 et la fonction error() renvoie DatagramTooLargeError. Il est dconseill
d'mettre des datagrammes de plus de 512 octets est en gnral. Mme s'ils sont mis avec succs,
ils seront probablement fragments au niveau de la couche IP avant d'arriver leur destination
nale.
listenSocket
Objet de la classe QUdpSocket constituant le canal de communication entre le sous-systme rseau
du noyau du systme d'exploitation et l'application.
datagram
Objet de la classe QByteArray contenant les donnes vues de la couche application de la
modlisation rseau.
senderAddress
Objet de la classe QHostAddress contenant la reprsentation de l'adresse de l'hte qui a mis le
datagramme reu par le serveur.
senderPort
Entier en format court contenant le numro de port utilis par l'hte qui a mis le datagramme
reu par le serveur.
<snipped/>
if (!listenSocket.bind(QHostAddress::Any , 8888 )) {
qDebug("Impossible de crer le socket en coute");
exit(EXIT_FAILURE) ;
}
spcie que le programme est en coute sur toutes les adresses IP des
interfaces de l'hte.
L'application est en coute sur le port numro 8888 uniquement.
Le le programme s'interrompt en cas d'erreur. On reprend ici le mme principe que dans les
autres programmes crits en Langage C.
QHostAddress::Any
Une fois la liaison en place, le programme attend les datagrammes provenant du client.
<snipped/>
if (listenSocket.waitForReadyRead(100)) {
if (listenSocket.hasPendingDatagrams()) ) {
datagram.resize(listenSocket.pendingDatagramSize());
if (listenSocket.readDatagram(datagram.data(), datagram.size(),
&senderAddress, &senderPort) == -1) {
listenSocket.close();
exit(EXIT_FAILURE);
}
msg = datagram.data();
<iostream>
<QtCore/QCoreApplication>
<QtCore/QTextStream>
<QtCore/QDebug>
<QtNetwork>
if (msg == "_EXIT_") {
listenSocket.close();
exit(EXIT_SUCCESS);
}
listenSocket.close();
}
return a.exec();
Note
Note
Dplacer le pointeur de la souris sur l'image, cliquer sur le bouton droit et lancer Afcher
l'image pour lire les messages.
Dans cette fentre, on implante trois objets.
pushButton
L'objet bouton, dont on a chang le texte afch, sert quitter le programme. Le code
correspondant l'utilisation du bouton se trouve dans le chier mainwindow.cpp.
msgLabel
Cet objet champ de texte est utilis pour l'afchage de la chane de caractres msg. C'est lors de la
rception d'un nouveau message que les caractres de ce champ sont modis.
senderLabel
Cet objet champ de texte est utilis pour l'afchage de l'adresse IP et le numro de port de l'metteur
du message. Comme dans le cas prcdent, il faut qu'un nouveau message ait t reu et que
l'metteur soit identi pour que ce champ soit modi.
En revenant au mode diter, on peut parcourir les diffrents chiers sources du projet.
main.cpp
Le programme principal est complt par dfaut lors de la cration d'un nouveau projet. notre
niveau, il n'est pas ncessaire de le modier. Son seul travail est d'afcher la fentre w de la classe
MainWindow avant d'entrer dans la boucle d'vnements (event loop).
mainwindow.h
Ce chier en-tte contient la dclaration de la classe MainWindow. C'est ce niveau que l'on dbute
l'dition de code avec l'ajout d'une mthode et de plusieurs membres privs. Le mot cl private
spcie que seuls les objets de la classe ont accs ces ressources.
Aprs les dclarations des membres et des mthodes de la classe MainWindow, ce chier contient le
code des mthodes. Les points importants ici sont le traitement des vnements et le traitement
des datagrammes rseau.
L'appel de la mthode connect() de la classe QObject cre une connexion entre le socket
listenSocket et le signal issu de la mthode readyRead().
Ds qu'un signal est reu par la mthode connect(), un datagramme est en attente de
lecture. Cette lecture et le traitement associ sont effectus l'aide du sous-programme
processPendingDatagrams() dont le code est donn dans le mme chier source.
Ici, l'appel la mthode connect() de la classe QObject cre une connexion entre l'objet pushButton
et le signal issu de la mthode clicked(). Ds que ce signal est reu, la mthode close() entrane
la n d'excution du programme.
Pour le traitement des datagrammes, c'est le code du sous-programme processPendingDatagrams() qui
assure la lecture, le passage en majuscules des caractres de la chane et la rmission. L'opration de
transformation des caractres en majuscules n'est qu'une illustration d'un traitement possible. Comme
la plupart des protocoles de l'Internet sont bass sur l'change de messages sous forme de chanes de
caractres, on utilise ici une forme minimaliste de traitement par requte - rponse.
QByteArray datagram;
datagram.resize(listenSocket->pendingDatagramSize());
if (listenSocket->readDatagram(datagram.data(), datagram.size(),
&senderAddress, &senderPort) == -1) {
listenSocket->close();
exit(EXIT_FAILURE);
}
msg = datagram.data();
qDebug() << "Depuis : " << senderAddress.toString() << ':' << senderPort;
qDebug() << Message : " << msg;
ui->senderLabel->setText(tr("Depuis : %1:%2")
. arg(senderAddress.toString())
. arg(senderPort));
ui->msgLabel->setText(tr("Message : \"%1\"")
. arg(msg));
msg = msg.toUpper();
datagram.clear();
datagram.append(msg);
On retrouve les lments du prcdent programme en mode console dans le code ci-dessus.
La mthode hasPendingDatagrams() renvoie la valeur boolenne vrai tant qu'un datagramme est
prsent dans la le d'attente.
La mthode readDatagram() collecte les donnes du datagramme ainsi que sa provenance en
identiant l'adresse de l'metteur et le numro de port source utilis.
La mthode setText() est appele pour changer le texte rfrenc par l'tiquette senderLabel
dans la fentre MainWindow. On fait apparatre l'adresse IP et le numro de port de l'metteur du
message.
La mthode setText() est nouveau appele pour changer le texte rfrenc par l'tiquette
msgLabel dans la fentre MainWindow. On fait apparatre ici le contenu de la chane de caractres
reue.
Une fois la chane de caractres transforme, elle est renvoye l'metteur l'aide de la mthode
writeDatagram().
Note
5.Documents de rfrence
Qt Network Programming
Qt Network Programming : page d'entre dans la documentation en ligne des bibliothques Qt sur
les communications rseau.
Modlisations rseau
Modlisations rseau : prsentation et comparaison des modlisations OSI et Internet.
10