Cours:QtTCP : Différence entre versions
(→connexion d'un client) |
(→Prépartion) |
||
(28 révisions intermédiaires par 2 utilisateurs non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
=Configuration du projet= | =Configuration du projet= | ||
− | Attention, il est nécessaire de rajouter | + | Attention, il est nécessaire de rajouter des librairies pour faire du réseau dans le projet : |
<source lang=cpp> | <source lang=cpp> | ||
// ajouter dans le fichier .pro | // ajouter dans le fichier .pro | ||
Ligne 7 : | Ligne 7 : | ||
</source> | </source> | ||
− | =Partie Serveur= | + | =Initialisation= |
+ | |||
+ | ==Partie Serveur== | ||
Une carte raspberryPi sera utilisée comme serveur. | Une carte raspberryPi sera utilisée comme serveur. | ||
Ligne 16 : | Ligne 18 : | ||
</source> | </source> | ||
− | ==Mise en place du serveur== | + | ===Mise en place du serveur=== |
− | On ajoute un attribut nommé {{Rouge|serveur}} de type QTcpServer à notre application, donc dans le fichier MainWindow.h, et on passe les paramètres au constructeur de la classe QTcpServer dans le fichier MainWindow.cpp | + | On ajoute un attribut nommé {{Rouge|serveur}} de type {{Rouge|QTcpServer}} à notre application, donc dans le fichier {{Rouge|MainWindow.h}}, et on passe les paramètres au constructeur de la classe {{Rouge|QTcpServer}} dans le fichier {{Rouge|MainWindow.cpp}} : |
<source lang=cpp> | <source lang=cpp> | ||
Ligne 26 : | Ligne 28 : | ||
... | ... | ||
private : | private : | ||
− | QTcpServer | + | QTcpServer monServeur; |
... | ... | ||
Ligne 43 : | Ligne 45 : | ||
</source> | </source> | ||
− | {{Question|En utilisant la méthode listen, dont voici un exemple d'utilisation, faîtes écouter votre serveur sur l'@ ip de votre carte sur le port de votre choix (>1000).}} | + | {{Question|En utilisant la méthode {{Rouge|listen}}, dont voici un exemple d'utilisation, faîtes écouter votre serveur sur l'@ ip de votre carte sur le port de votre choix (>1000).}} |
<source lang=cpp> | <source lang=cpp> | ||
monServeur.listen(QHostAddress("192.168.0.1"),monNumeroDePort); | monServeur.listen(QHostAddress("192.168.0.1"),monNumeroDePort); | ||
+ | ou | ||
+ | monServeur.listen(QHostAddress(QHostAddress::AnyIPv4),monNumeroDePort); | ||
</source> | </source> | ||
{{Question|afficher un message indiquant la réussite ou l'échec du démarrage du serveur.}} | {{Question|afficher un message indiquant la réussite ou l'échec du démarrage du serveur.}} | ||
− | ==connexion d'un client== | + | ===connexion d'un client=== |
Lorsqu'un client se connecte sur votre serveur, celui-ci émet un signal {{Rouge|newConnection}}. | Lorsqu'un client se connecte sur votre serveur, celui-ci émet un signal {{Rouge|newConnection}}. | ||
− | {{Question|Connectez vous sur ce signal pour afficher un message d'information à chaque nouvelle connexion}} | + | {{Question|Connectez vous sur ce signal pour afficher un message d'information à chaque nouvelle connexion.}} |
− | ''Remarque :'' il faudra bien évidemment créer un slot dans la classe MainWindow pour ensuite réaliser la connexion sur le signal émis | + | ''Remarque :'' il faudra bien évidemment créer un slot dans la classe {{Rouge|MainWindow}} pour ensuite réaliser la connexion sur le signal émis. |
− | == | + | ==Partie Client== |
− | === | + | ===Mise en place du client=== |
− | |||
− | + | On ajoute un attribut nommé {{Rouge|clientSocket}} de type {{Rouge|QTcpSocket}} à notre application, donc dans le fichier {{Rouge|MainWindow.h}}, et on passe les paramètres au constructeur de la classe {{Rouge|QTcpSocket}} dans le fichier {{Rouge|MainWindow.cpp}} : | |
− | |||
− | |||
− | |||
− | |||
Ligne 77 : | Ligne 76 : | ||
... | ... | ||
private : | private : | ||
− | QTcpSocket | + | QTcpSocket clientSocket; |
... | ... | ||
Ligne 87 : | Ligne 86 : | ||
:QMainWindow(parent), | :QMainWindow(parent), | ||
ui(new Ui::MainWindow), | ui(new Ui::MainWindow), | ||
− | + | clientSocket(this) | |
{ | { | ||
ui->setupUi(this); | ui->setupUi(this); | ||
Ligne 94 : | Ligne 93 : | ||
</source> | </source> | ||
− | + | ===Connexion sur le serveur=== | |
− | ==Connexion sur le serveur== | ||
Pour se connecter sur un serveur, il suffit d'appeler la méthode {{Rouge|connectToHost}} en spécifiant l'@ du serveur ainsi que le port d'écoute. | Pour se connecter sur un serveur, il suffit d'appeler la méthode {{Rouge|connectToHost}} en spécifiant l'@ du serveur ainsi que le port d'écoute. | ||
Ligne 106 : | Ligne 104 : | ||
*le signal {{Rouge|connected}} est émis lorsque la connexion est établie sur le serveur. | *le signal {{Rouge|connected}} est émis lorsque la connexion est établie sur le serveur. | ||
− | *créer un slot dans votre MainWindow et connecter le signal émis par l'objet client sur ce slot. | + | *créer un slot dans votre {{Rouge|MainWindow}} et connecter le signal émis par l'objet client sur ce slot. |
+ | |||
+ | ===Reconnexion=== | ||
+ | |||
+ | Pour le moment, dès que l'application serveur est fermée, le client est nécessairement déconnecté, mais il ne relance pas de connexion. | ||
+ | |||
+ | Nous allons utiliser un {{Rouge|QTimer}} qui cherchera à rétablir régulièrement cette connexion sur le serveur. | ||
+ | |||
+ | *Ajouter un attribut de type {{Rouge|QTimer}} dans la classe MainWindow. | ||
+ | *Définir la durée du timer à 100ms (méthode {{Rouge|setInterval}} ). | ||
+ | *Le {{Rouge|QTimer}} émettra un signal {{Rouge|timeout}} toutes les 100ms. | ||
+ | *Connectez vous sur ce signal un créant un slot {{Rouge|reconnect}} dans la classe {{Rouge|MainWindow}}. | ||
+ | *C'est dans ce slot que l'on appelle la méthode {{Rouge|connectToHost}}. | ||
+ | *Pour lancer/arrêter un {{Rouge|QTimer}}, on utilise les méthodes {{Rouge|start}} et {{Rouge|stop}}. | ||
+ | |||
+ | #Au démarrage de l'application, on lance le {{Rouge|QTimer}}. | ||
+ | #Lorsqu'on est connecté (signal {{Rouge|connnected}}) on arrête le {{Rouge|QTimer}}. | ||
+ | #lorsqu'on est déconnecté (signal {{Rouge|disconnected}}) on lance à nouveau le {{Rouge|QTimer}}. | ||
+ | |||
+ | {{Question|Mettre en place cette partie}} | ||
+ | |||
+ | =Echange de données= | ||
+ | |||
+ | Dans cette partie, le serveur enverra une donnée, et le client va recevoir l'information. | ||
+ | |||
+ | Pratiquement, on utilisera un bouton côté serveur dont on enverra l'état (0 ou 1), et une led ou juste un affichage de texte dans la console côté client. | ||
+ | |||
+ | |||
+ | ==Serveur== | ||
+ | |||
+ | ===Prépartion=== | ||
+ | Pour l'envoi ou la réception de données, nous avons besoin d'un {{Rouge|QTcpSocket}}. Celui-ci existe déjà pour le client, nous devons en créer un sur le serveur à chaque nouvelle connexion. | ||
+ | |||
+ | {{Todo|Apporter les modifications suivantes :}} | ||
+ | *ajout d'un attribut de type {{Rouge|QTcpSocket *}} nommé {{Rouge|serveurSocket}} | ||
+ | *dans votre méthode exécutée à chaque connexion d'un client, ajouter : | ||
+ | serveurSocket = serveur.nextPendingConnection(); | ||
+ | Exemple : | ||
+ | <source lang=cpp> | ||
+ | // mainwindow.h | ||
+ | ... | ||
+ | ... | ||
+ | private : | ||
+ | QTcpSocket * serveurSocket; | ||
+ | ... | ||
+ | |||
+ | |||
+ | //mainwindow.cpp | ||
+ | ... | ||
+ | void MainWindow::newConnection() | ||
+ | { | ||
+ | qDebug()<<"connexion d'un nouveau client"; | ||
+ | serveurSocket = monServeur.nextPendingConnection(); | ||
+ | } | ||
+ | ... | ||
+ | </source> | ||
+ | |||
+ | ===Envoyer des données=== | ||
+ | |||
+ | Pour envoyer un nombre entier sur la connexion, vous pouvez utiliser la méthode suivante, qu'il faudra bien entendue déclarer dans le fichier {{Rouge|Mainwindow.h}} : | ||
+ | |||
+ | <source lang=cpp> | ||
+ | void MainWindow::sendMessage(int val) | ||
+ | { | ||
+ | QByteArray block; | ||
+ | QDataStream out(&block, QIODevice::WriteOnly); | ||
+ | out.setVersion(QDataStream::Qt_5_0); | ||
+ | out << val; | ||
+ | // qDebug()<<"message envoyé :"<<val; | ||
+ | serveurSocket->write(block); | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | {{Todo|Faire les modifications.}} | ||
+ | |||
+ | ===Utilisation=== | ||
+ | |||
+ | On utilisera 2 boutons sur l'écran graphique (bpOn et bpOff) | ||
+ | |||
+ | On émettra la valeur 0 à chaque appui sur ...suspens.... bpOff, et donc 1 pour bpOn ! | ||
+ | |||
+ | {{Question|Let's go !}} | ||
+ | |||
+ | |||
+ | Vous pourrez utiliser un bouton poussoir connecté sur un GPIO si vous avez le temps. | ||
+ | |||
+ | ==Client== | ||
+ | |||
+ | ===Préparation=== | ||
+ | |||
+ | On utilise un {{Rouge|QDataStream}} pour lire les données reçues sur la connexion. | ||
+ | |||
+ | On le mettra en place de la façon suivante : | ||
+ | *ajout d'un attribut {{Rouge|dataIn}} | ||
+ | *association {{Rouge|dataIn}}, {{Rouge|clientSocket}} dans le constructeur | ||
+ | |||
+ | <source lang=cpp> | ||
+ | // mainwindow.h | ||
+ | ... | ||
+ | ... | ||
+ | private : | ||
+ | QDataStream dataIn; | ||
+ | ... | ||
+ | |||
+ | |||
+ | //mainwindow.cpp | ||
+ | ... | ||
+ | MainWindow::MainWindow(QWidget *parent) | ||
+ | :QMainWindow(parent), | ||
+ | ui(new Ui::MainWindow), | ||
+ | clientSocket(this) | ||
+ | { | ||
+ | dataIn.setDevice(&clientSocket); | ||
+ | ui->setupUi(this); | ||
+ | ... | ||
+ | } | ||
+ | ... | ||
+ | </source> | ||
+ | |||
+ | {{Todo|Faire les modifications.}} | ||
+ | |||
+ | ===Recevoir des données=== | ||
+ | |||
+ | Pour recevoir un nombre entier sur la connexion, nous devons : | ||
+ | *récupérer le signal {{Rouge|readyRead}} du {{Rouge|clientSocket}} et le connecter sur une méthode {{Rouge|getValue}}. | ||
+ | *lire le flux de données. | ||
+ | |||
+ | <source lang=cpp> | ||
+ | void MainWindow::getValue() | ||
+ | { | ||
+ | dataIn.startTransaction(); | ||
+ | if (!dataIn.commitTransaction()) return; | ||
+ | int valeur; | ||
+ | dataIn >> valeur; | ||
+ | //qDebug()<< valeur; | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | {{Todo|Faire les modifications.}} | ||
+ | |||
+ | ===Utilisation=== | ||
+ | |||
+ | On utilisera dans un premier temps un qDebug, puis une led branchée sur un GPIO pour afficher la valeur reçue. | ||
+ | |||
+ | {{Question|Let's go !}} |
Version actuelle datée du 12 octobre 2024 à 09:43
Configuration du projet
Attention, il est nécessaire de rajouter des librairies pour faire du réseau dans le projet :
// ajouter dans le fichier .pro
QT += network
Initialisation
Partie Serveur
Une carte raspberryPi sera utilisée comme serveur.
Vous aurez besoin de l'adresse (notée @ par la suite) ip de votre carte, pour ce faire vous pouvez dans une console lancer la commande :
ping ras-pi-xx
Mise en place du serveur
On ajoute un attribut nommé serveur de type QTcpServer à notre application, donc dans le fichier MainWindow.h, et on passe les paramètres au constructeur de la classe QTcpServer dans le fichier MainWindow.cpp :
// mainwindow.h
...
#include <QTcpServer>
...
private :
QTcpServer monServeur;
...
//mainwindow.cpp
...
MainWindow::MainWindow(QWidget *parent)
:QMainWindow(parent),
ui(new Ui::MainWindow),
serveur(this)
{
ui->setupUi(this);
}
...
En utilisant la méthode listen, dont voici un exemple d'utilisation, faîtes écouter votre serveur sur l'@ ip de votre carte sur le port de votre choix (>1000).
monServeur.listen(QHostAddress("192.168.0.1"),monNumeroDePort);
ou
monServeur.listen(QHostAddress(QHostAddress::AnyIPv4),monNumeroDePort);
afficher un message indiquant la réussite ou l'échec du démarrage du serveur.
connexion d'un client
Lorsqu'un client se connecte sur votre serveur, celui-ci émet un signal newConnection.
Connectez vous sur ce signal pour afficher un message d'information à chaque nouvelle connexion.
Remarque : il faudra bien évidemment créer un slot dans la classe MainWindow pour ensuite réaliser la connexion sur le signal émis.
Partie Client
Mise en place du client
On ajoute un attribut nommé clientSocket de type QTcpSocket à notre application, donc dans le fichier MainWindow.h, et on passe les paramètres au constructeur de la classe QTcpSocket dans le fichier MainWindow.cpp :
// mainwindow.h
...
#include <QTcpSocket>
...
private :
QTcpSocket clientSocket;
...
//mainwindow.cpp
...
MainWindow::MainWindow(QWidget *parent)
:QMainWindow(parent),
ui(new Ui::MainWindow),
clientSocket(this)
{
ui->setupUi(this);
}
...
Connexion sur le serveur
Pour se connecter sur un serveur, il suffit d'appeler la méthode connectToHost en spécifiant l'@ du serveur ainsi que le port d'écoute.
monClient.connectToHost("192.168.0.1",monNumeroDePort);
Connectez vous sur votre serveur
Vérifier que votre client s'est bien connecté :
- le signal connected est émis lorsque la connexion est établie sur le serveur.
- créer un slot dans votre MainWindow et connecter le signal émis par l'objet client sur ce slot.
Reconnexion
Pour le moment, dès que l'application serveur est fermée, le client est nécessairement déconnecté, mais il ne relance pas de connexion.
Nous allons utiliser un QTimer qui cherchera à rétablir régulièrement cette connexion sur le serveur.
- Ajouter un attribut de type QTimer dans la classe MainWindow.
- Définir la durée du timer à 100ms (méthode setInterval ).
- Le QTimer émettra un signal timeout toutes les 100ms.
- Connectez vous sur ce signal un créant un slot reconnect dans la classe MainWindow.
- C'est dans ce slot que l'on appelle la méthode connectToHost.
- Pour lancer/arrêter un QTimer, on utilise les méthodes start et stop.
- Au démarrage de l'application, on lance le QTimer.
- Lorsqu'on est connecté (signal connnected) on arrête le QTimer.
- lorsqu'on est déconnecté (signal disconnected) on lance à nouveau le QTimer.
Echange de données
Dans cette partie, le serveur enverra une donnée, et le client va recevoir l'information.
Pratiquement, on utilisera un bouton côté serveur dont on enverra l'état (0 ou 1), et une led ou juste un affichage de texte dans la console côté client.
Serveur
Prépartion
Pour l'envoi ou la réception de données, nous avons besoin d'un QTcpSocket. Celui-ci existe déjà pour le client, nous devons en créer un sur le serveur à chaque nouvelle connexion.
Apporter les modifications suivantes :
- ajout d'un attribut de type QTcpSocket * nommé serveurSocket
- dans votre méthode exécutée à chaque connexion d'un client, ajouter :
serveurSocket = serveur.nextPendingConnection();
Exemple :
// mainwindow.h
...
...
private :
QTcpSocket * serveurSocket;
...
//mainwindow.cpp
...
void MainWindow::newConnection()
{
qDebug()<<"connexion d'un nouveau client";
serveurSocket = monServeur.nextPendingConnection();
}
...
Envoyer des données
Pour envoyer un nombre entier sur la connexion, vous pouvez utiliser la méthode suivante, qu'il faudra bien entendue déclarer dans le fichier Mainwindow.h :
void MainWindow::sendMessage(int val)
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_0);
out << val;
// qDebug()<<"message envoyé :"<<val;
serveurSocket->write(block);
}
Utilisation
On utilisera 2 boutons sur l'écran graphique (bpOn et bpOff)
On émettra la valeur 0 à chaque appui sur ...suspens.... bpOff, et donc 1 pour bpOn !
Vous pourrez utiliser un bouton poussoir connecté sur un GPIO si vous avez le temps.
Client
Préparation
On utilise un QDataStream pour lire les données reçues sur la connexion.
On le mettra en place de la façon suivante :
- ajout d'un attribut dataIn
- association dataIn, clientSocket dans le constructeur
// mainwindow.h
...
...
private :
QDataStream dataIn;
...
//mainwindow.cpp
...
MainWindow::MainWindow(QWidget *parent)
:QMainWindow(parent),
ui(new Ui::MainWindow),
clientSocket(this)
{
dataIn.setDevice(&clientSocket);
ui->setupUi(this);
...
}
...
Recevoir des données
Pour recevoir un nombre entier sur la connexion, nous devons :
- récupérer le signal readyRead du clientSocket et le connecter sur une méthode getValue.
- lire le flux de données.
void MainWindow::getValue()
{
dataIn.startTransaction();
if (!dataIn.commitTransaction()) return;
int valeur;
dataIn >> valeur;
//qDebug()<< valeur;
}
Utilisation
On utilisera dans un premier temps un qDebug, puis une led branchée sur un GPIO pour afficher la valeur reçue.