Vous êtes sur la page 1sur 10

Initiation au dveloppement Qt sur les sockets

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.

Table des matires


1. Copyright et Licence ............................................................................................................... 1
1.1. Meta-information .......................................................................................................... 1
2. Contexte de dveloppement .................................................................................................... 2
2.1. Bibliothques Qt ........................................................................................................... 2
2.2. Instructions d'excution ................................................................................................ 2
2.3. Bibliothques utilises .................................................................................................. 4
3. Programme serveur UDP en mode console .............................................................................. 4
3.1. Utilisation des sockets avec le serveur UDP console ........................................................ 4
3.2. Code source complet .................................................................................................... 5
4. Programme serveur UDP en mode graphique ........................................................................... 6
4.1. Utilisation des sockets avec le serveur UDP graphique .................................................... 7
4.2. Traitement des vnements et des datagrammes ............................................................ 8
5. Documents de rfrence ......................................................................................................... 9

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.

Initiation au dveloppement Qt sur les sockets

Initiation au dveloppement Qt sur les sockets

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.

Initiation au dveloppement Qt sur les sockets

Initiation au dveloppement Qt sur les sockets


Le programme serveur, nogui-udp-listener

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.

Initiation au dveloppement Qt sur les sockets

Initiation au dveloppement Qt sur les sockets

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.

3.Programme serveur UDP en mode console


Avec l'environnement intgr de dveloppement QtCreator, il est possible de crer une application en
mode console.
partir de l'cran d'accueil, il faut crer un nouveau projet et choisir Qt Console Application dans la
catgorie Application.
L'intrt de cette tape est de produire un chier source unique de taille rduite dans lequel on trouve
l'ensemble des appels de bibliothques Qt.

3.1.Utilisation des sockets avec le serveur UDP console


Avec les bibliothques Qt, on retrouve les lments classiques de reprsentation des communications
rseau.

Initiation au dveloppement Qt sur les sockets

Initiation au dveloppement Qt sur les sockets


QUdpSocket listenSocket;
QByteArray datagram;
QHostAddress senderAddress;
quint16 senderPort;

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

La mthode waitForReadyRead(100) bloque l'excution du programme pendant 100ms, le temps


de dtecter un vnement de rception de donnes sur le socket en coute.
Si un datagramme est en attente, on procde sa lecture.
On redimensionne le tableau des donnes en fonction de la taille du datagramme reu.
On stocke les donnes du datagramme dans la chane de caractres msg.
Enn, l'mission de datagramme du serveur vers le client utilise la fonction writeDatagram avec un jeu
de paramtres identique l'opration de lecture.

3.2.Code source complet


#include
#include
#include
#include
#include

<iostream>
<QtCore/QCoreApplication>
<QtCore/QTextStream>
<QtCore/QDebug>
<QtNetwork>

int main(int argc, char *argv[])

Initiation au dveloppement Qt sur les sockets

Initiation au dveloppement Qt sur les sockets


{

QCoreApplication a(argc, argv);


QUdpSocket listenSocket;
QByteArray datagram;
QHostAddress senderAddress;
quint16 senderPort;
QString msg;
if (!listenSocket.bind(QHostAddress::Any, 8888)) {
qDebug("Impossible de crer le socket en coute");
exit(EXIT_FAILURE);
}
while (1) {
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();
qDebug() << "Depuis : " << senderAddress.toString() << ':' << senderPort;
qDebug() << "Message : " << msg;
msg = msg.toUpper();
datagram.clear();
datagram.append(msg);

if (listenSocket.writeDatagram(datagram, senderAddress, senderPort) == -1) {


qDebug("mission du message modifi impossible");
listenSocket.close();
exit(EXIT_FAILURE);
}

if (msg == "_EXIT_") {
listenSocket.close();
exit(EXIT_SUCCESS);
}

listenSocket.close();
}

return a.exec();

Note

Le code complet du projet est disponible via le chier nogui-udp-listener.tar.gz.

4.Programme serveur UDP en mode graphique


Dans cette section, on cre une nouvelle application graphique avec l'environnement intgr de
dveloppement QtCreator. partir de l'cran d'accueil, il faut crer un nouveau projet et choisir
Application graphique Qt dans la catgorie Projet Qt Widget.
Relativement la section prcdente dans laquelle on utilisait un chier source unique de taille limite,
on se trouve face un pr dcoupage des chiers dni par dfaut. Avec cette organisation des sources,
la gestion de la fentre graphique est spare du code proprement dit. Tous les attributs de la fentre
utilise sont dcrits dans le chier mainwindow.ui.

Initiation au dveloppement Qt sur les sockets

Initiation au dveloppement Qt sur les sockets

4.1.Utilisation des sockets avec le serveur UDP graphique


Puisque cette section est consacre une application graphique, on commence par dcrire le volet
interface utilisateur.
Une fois le projet ouvert, on slectionne l'onglet Formulaires puis le chier de description de la fentre
graphique mainwindow.ui.

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.

Initiation au dveloppement Qt sur les sockets

Initiation au dveloppement Qt sur les sockets


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.

4.2.Traitement des vnements et des datagrammes


Dans ce programme, deux types d'vnements sont scruts : l'arrive d'un nouveau datagramme et le
clic sur le bouton Quitter. Le code correspondant la scrutation des vnements est dcrit dans la
mthode MainWindow du chier mainwindow.cpp.
<snipped/>
QObject::connect(listenSocket, SIGNAL(readyRead()),
this, SLOT(processPendingDatagrams()));
QObject::connect(ui->pushButton, SIGNAL(clicked()),
this, SLOT(close()));

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.

Initiation au dveloppement Qt sur les sockets

Initiation au dveloppement Qt sur les sockets


<snipped/>
void MainWindow::processPendingDatagrams()
{
while (listenSocket->hasPendingDatagrams())

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

if (listenSocket->writeDatagram(datagram, senderAddress, senderPort) == -1) {


qDebug("mission du message modifi impossible");
listenSocket->close();
exit(EXIT_FAILURE);
}
}

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

Le code complet du projet est disponible via le chier gui-udp-listener.tar.gz.

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.

Initiation au dveloppement Qt sur les sockets

Initiation au dveloppement Qt sur les sockets


Adressage IPv4
Adressage IPv4 : 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 local : support sur la conguration des interfaces rseau.
Il permet notamment de relever les adresses IP des htes en communication.

Initiation au dveloppement Qt sur les sockets

10

Vous aimerez peut-être aussi