Socket QT PDF
Socket QT PDF
Socket QT PDF
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
1
2
2
2
3
4
4
5
6
6
7
8
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 DocBook1 XML sur un systme Debian GNU/Linux2. Il est disponible en version imprimable au format
PDF : socket-qt.pdf3.
1
2
3
http://www.docbook.org
http://www.debian.org
http://www.inetdoc.net/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.c4
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.
http://www.inetdoc.net/dev/socket-c/socket-c.udp.client.html#socket-c.udp.client.source
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 sockets5. On ne s'intresse ici qu' l'utilisation de la brique rseau des bibliothques Qt.
http://www.inetdoc.net/dev/socket-c/
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.
Le le programme s'interrompt en cas d'erreur. On reprend ici le mme principe que dans les autres programmes crits
en Langage C.
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.
6
http://www.inetdoc.net/dev/socket-qt/qtcreator/nogui-udp-listener.tar.gz
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.
La mthode processPendingDatagrams() contient tous les traitements de rception, de transformation et de r mission
des messages. Cette mthode utilise les membres dclars dans la classe.
On retrouve ici la liste des variables du programme de la section prcdente en plus du pointeur de fentre ui (user
interface) et des deux champs de texte prsents plus haut.
private:
Ui::MainWindow *ui;
QLabel *senderLabel, *msgLabel;
QUdpSocket *listenSocket;
QHostAddress senderAddress;
quint16 senderPort;
QString msg;
mainwindow.cpp
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 Programming8 : page d'entre dans la documentation en ligne des bibliothques Qt sur les communications
rseau.
Modlisations rseau
Modlisations rseau9 : prsentation et comparaison des modlisations OSI et Internet.
Adressage IPv4
Adressage IPv410 : support complet sur l'adressage du protocole de couche rseau de l'Internet (IP).
Conguration d'une interface rseau
Conguration d'une interface de rseau local11 : support sur la conguration des interfaces rseau. Il permet notamment
de relever les adresses IP des htes en communication.
http://www.inetdoc.net/dev/socket-qt/qtcreator/gui-udp-listener.tar.gz
http://doc.qt.nokia.com/4.7/network-programming.html
http://www.inetdoc.net/articles/modelisation/
10
http://www.inetdoc.net/articles/adressage.ipv4/
11
http://www.inetdoc.net/travaux_pratiques/cong.interface.lan/
8
9