Désolé d'avance si le sujet a déjà été fait mais il ne me semble pas avoir trouvé. Je n'ai pas l'habitude de demander de l'aide, je finis toujours par trouver mais là je ne vois vraiment pas.
Donc, j'ai suivi le cours "Programmer avec le langage C++" et en étant à la dernière partie avec Qt, le réseau, je rencontre un problème. J'ai écrit exactement le même code que dans le cours, tout semble fonctionner et pourtant quand je lance le serveur, puis mon client (ou mes clients), l'envoi d'un message ne fonctionne pas.
Ayant retracé d'où pouvait venir le problème, j'ai remarqué que le QByteArray était bien rempli d'un Quint16 et de mon QString, la taille variant bien en fonction de la taille de la chaine de caractère. Aussi côté serveur, le QDataStream qui lit la socket reçoit bien tous les octets envoyés et son statut montre qu'il n'est pas défaillant. Pourtant, quand je stocke les informations du QDataStream dans Quint16 tailleMessage puis QString message, ils sont respectivement rempli par 0 et une chaine vide (je suppose vu que rien ne s'affiche).
void FenServeur::donneesRecues()
{
// 1 : on reçoit un paquet (ou un sous-paquet) d'un des clients
// On détermine quel client envoie le message (recherche du QTcpSocket du client)
QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
if (socket == 0) // Si par hasard on n'a pas trouvé le client à l'origine du signal, on arrête la méthode
return;
// Si tout va bien, on continue : on récupère le message
QDataStream in(socket);
if (tailleMessage == 0) // Si on ne connaît pas encore la taille du message, on essaie de la récupérer
{
if (socket->bytesAvailable() < int(sizeof(quint16))) // On n'a pas reçu la taille du message en entier
return;
in >> tailleMessage; // Si on a reçu la taille du message en entier, on la récupère
}
// Si on connaît la taille du message, on vérifie si on a reçu le message en entier
if (socket->bytesAvailable() < tailleMessage) // Si on n'a pas encore tout reçu, on arrête la méthode
return;
// Si ces lignes s'exécutent, c'est qu'on a reçu tout le message : on peut le récupérer !
QString message;
in >> message;
// 2 : on renvoie le message à tous les clients
envoyerATous(message);
// 3 : remise de la taille du message à 0 pour permettre la réception des futurs messages
tailleMessage = 0;
}
void FenClient::on_boutonEnvoyer_clicked()
{
QByteArray paquet;
QDataStream out(&paquet, QIODevice::WriteOnly);
// On prépare le paquet à envoyer
QString messageAEnvoyer = tr("<strong>") + pseudo->text() +tr("</strong> : ") + message->text();
out << quint16(0);
out << messageAEnvoyer;
out.device()->seek(0);
out << (quint16(paquet.size()) - quint16(sizeof(quint16)));
std::cout<<"octets ecrits : "<<socket->write(paquet)<<std::endl; // On envoie le paquet
message->clear(); // On vide la zone d'écriture du message
message->setFocus(); // Et on remet le curseur à l'intérieur
}
Je tiens également à préciser que j'ai fait le test avec le code fourni par le prof (bien que tout à fait identique normalement) et même résultat. Aussi, comme je fais le test en local ça ne devrait pas importer, mais mon port est bien ouvert sur mon réseau.
Si vous avez des idées d'où vient le problème, ou besoin de plus d'informations, faites-moi signe.
Note : c'est pas le code d'un prof mais le cours de ce site, qui est a éviter. Il enseigne un C++ retraité, et c'est la même chose sur Qt, avec certain code proposé qui ne marchent plus.
@PieWar : Oui mes clients sont bien connectés, à coup de std::cout j'ai vérifié que le serveur recevait bien le paquet comme je l'avais expliqué, il reçoit bien le paquet de la bonne taille donc c'est que le client est connecté. Je vais voir comment fonctionne QDebug, j'essaie ça et vous tiens au courant.
@K4kugen : Merci pour les liens, je les consulterais pour apprendre à mieux programmer. Actuellement je suis à l'université et j'ai bien l'impression qu'on nous apprend comme tu dis un C++ retraité, les cours sont totalement vieillissant. En fait j'ai uniquement suivi les chapitres de Qt du cours d'OC, je voulais apprendre à l'utiliser car il facilite l'implémentation du réseau mais bien sûr c'est la seule partie que je n'arrive pas à faire fonctionner.
EDIT : @PieWar : J'ai bien peur de ne pas comprendre comment fonctionne, ni comment me servir du QDebug... Si tu peux m'éclairer.
- Edité par CharlyBollinger 12 juillet 2019 à 14:19:58
Si tu suis uniquement les partie Qt, tu ne devrais pas devoir désapprendre beaucoup de chose, mais fait quand même attention, comme dit plus haut, certains codes proposés ne compilent même pas. Si tu es à l'aise avec l'anglais, Qt propose ses propres tutos : https://doc.qt.io/qt-5/gettingstarted.html
Pour QDebug, pense bien aux parenthèses (et l'include) :
Il permet d'afficher des variables/strings dans la console (pour une utilisation simple), mais un std::cout fait l'affaire (pour cette utilisation simpliste)
La fonction qDegub(), qui s'utilise comme ceci: qDebug()<<QString; sert a aficher du texte dans la partie 'sortie de l’application' de QT, alors que l'appli est en cours d’exécution. Cela peut servir a voir si une fonction s'est lancée, etc...
D'accord donc ça fait exactement comme ce que j'avais fait avec des std::cout, le message est vide comme je disais dans le sujet mais quand je vérifie le nombre d'octet côté serveur avec socket->bytesAvailable() j'ai bien le bon nombre d'octets qui sont disponible. La question est pourquoi il ne me les range pas dans mon QString (et mon Quint16), ou alors si il le fait bien pourquoi les données semblent vides.
"Pourtant, quand je stocke les informations du QDataStream dans Quint16 tailleMessage puis QString message, ils sont respectivement rempli par 0 et une chaine vide (je suppose vu que rien ne s'affiche)."
, tu essai de stocker ca a quel niveau? Coté serveur ou Client?
Côté serveur bien sûr. Car le client envoie bien le paquet, en effet si côté serveur je reçois bytesAvailable avec la valeur de la taille en octet du paquet envoyé côté client, cela veut dire que le paquet est réçu côté serveur. Or quand je stocke ces données dans un Quint16 pour la taille puis un QString pour le reste du message j'obtiens les valeurs 0 et "".
(Là du coup j'essaie de refaire totalement autrement de mes propres moyens avec la doc Qt, mais bon je ne comprends quand même pas ce qui n'allait pas avec le code dont on parle)
Le soucis que tu as, vient probablement du fait que lorsque tu vas lire la taille, le client a probablement déjà commencé à envoyer la chaîne de caractères, du coup BytesAvailiable renvoie une valeur supérieure à ce que tu attendais et tu te retrouves dans la panade (TCP/IP te garantis que les paquets arriveront dans l'ordre où ils ont été émis, pas qu'ils n'auront pas été scindés ou regroupés...). Rien ne te garantit que ce qui se trouve dans un socket est une trame complète, rien ne garantit non plus, qu'il n'y a pas un bout de la trame suivante. La programmation réseau met à mal notre perception du temps, a cause de ça, c'est peut être la programmation la plus difficile qui soit.
Lorsqu'on fait de la communication réseau, on travaille avec un protocole. Un protocole simple (et relativement efficace) est de toujours commencer une communication par un "magic number", c'est facile à mettre en oeuvre, tu lis les 4 premiers octets, tu cast en int et si tu ne retrouve pas le "magic number", tu déconnectes. Derrière, tu passes la taille de ce que tu vas envoyer, puis généralement un checksum (classiquement un crc32), le magic number te permet de vérifier que tu es bien synchro, la taille de ce qui suit te permet de savoir où se finit la trame courante et le checksum que tu as bien reçu ce qui t'as été envoyé. Là tu peux faire face à la plupart des pannes. Pour faire face aux malveillances, tu passes au chiffrement, c'est un peu plus compliqué dans la mise en oeuvre, mais pas dans le principe.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
GitHub
GitHub