Partage
  • Partager sur Facebook
  • Partager sur Twitter

QTcpServer

Bug

Sujet résolu
    24 juillet 2021 à 20:23:39

    Bonjour à vous, j'ai implémenté JSON-RPC 2.0 à travers l'objet QTcpServer que Qt fournie par défaut. Voici mon code :
    TCPServerController.cpp : https://pastebin.com/zsCYD9Vw

    Je vous délivre le micro bug, que j'ai pu observer o_O. C'est même pas un bug Client/Serveur RPC c'est plus un bug externe.
    Le serveur écoute sur le port 27556. Je regarde un peu, et je fais donc http://localhost:27556/ dans mon navigateur.
    Donc, juste pour testé... comme ça par hasard. Le serveur détecte une nouvelle connexion. Et ne fait rien.
    Moi de mon côté, sur le logiciel, je me connecte, tout comme il faut, et genre là... ça ne fait strictement rien. J'ai d'une part réussi à me connecté au serveur (localhost ici), mais d'autre pas, j'ai pu envoyer la requête RPC "subscribe"... Mais le serveur ne me répond pas. Si je ne get pas le http://localhost:27556/ mais que je me connecte directement avec le logiciel, bah ça marche :lol:.
    Mais bon, si on met l'url du serveur + :27556, et que ça fait bugger le serveur, bah c'est pas ouf :pirate:.

    c'est pour ça que je sollicite votre aide.

    Cordialement.

    -
    Edité par Loopite 24 juillet 2021 à 20:26:18

    • Partager sur Facebook
    • Partager sur Twitter
      31 juillet 2021 à 10:46:50

      Bonjour, je n'ai toujours pas trouvé de solution, avez-vous une idée ?
      • Partager sur Facebook
      • Partager sur Twitter
        31 juillet 2021 à 13:31:53

        Votre question ne me semble pas claire.

        Votre code me semble pas très fiable car vous avez oublié la base : TCP/IP est orienté flux, pas message/paquet.

        Je ne vois non plus le code qui copie l'objet JSON dans le tableau qui contient la réponse à la requête.

        N'oublier pas qu'un navigateur Web ne fait pas que se connecter à une socket, il envoie une ou plusieurs requêtes HTTP. Si votre serveur les interprètent mal, il peut faire nimp.

        Le débogueur est votre ami.

        -
        Edité par bacelar 31 juillet 2021 à 13:32:13

        • Partager sur Facebook
        • Partager sur Twitter
        Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
          31 juillet 2021 à 20:05:35

          Bonjour, tout d'abord, merci de votre réponse.
          Pour reprendre : "Votre code me semble pas très fiable car vous avez oublié la base : TCP/IP est orienté flux, pas message/paquet.", comment, vous auriez écrit la fonction permettant d'envoyer des messages, (la fonction sendMessage) et la fonction qui permet d'en recevoir (la fonction receive).

          "Je ne vois non plus le code qui copie l'objet JSON dans le tableau qui contient la réponse à la requête." Je ne comprends pas ce que vous voulez dire par le code qui copie l'objet JSON dans le tableau. Pourriez vous être plus explicite ?
          Ce que je peux vous dire, c'est que le client envoie une requête RPC, en JSON au serveur, et le serveur lui répond. Le principe de JSON-RPC et d'appeler une fonction via la requête RPC. Pour avoir un maximum de détails, vous pouvez consulter : https://www.jsonrpc.org/specification.

          Afin de pouvoir vous éclaircir sur mon problème, je vais plus le détailler.

          J'ai un code serveur, que j'ai donc joint, et un code client, qui lui permet de se connecter au serveur en local.
          Pour illustrer plus facilement mes propos, je vous propose de considérer toutes les actions inhérentes à l'exemple ci dessous :
          - Le serveur socket (TCP) écoute sur le port 27556.
          - Un nouveau client se connecte via le logiciel au serveur (connexion effectuée avec succès).
          A partir de là, tout fonctionne vraiment. Rien a dire, le serveur peut avoir une nouvelle connexion, si le client se connecte via le logiciel.
          - Un 2ème client se connecte au serveur en faisant un curl :
          curl -i -X GET http://localhost:27556
          Après avoir fait un maximum de debugs, comme vous me l'avez conseillé, le serveur génère donc un nouveau pointeur, (voir la ligne 26 du code émanant de https://pastebin.com/zsCYD9Vw). Donc jusque là, bah c'est bon, le second client est connecté au serveur. Mais là il y a un problème.
          - Un troisième client se connecte au serveur, cette fois si via le logiciel comme le client numéro 1.
          Et là, pareil, le serveur dit que le client est connecté, le client envoie un message JSON au serveur, le serveur ne reçoit pas le message.
          C'est comme si le connect ligne 28 ne marchait pas.
          Genre à cause du deuxième client, bah le serveur ne peut plus recevoir de messages, le serveur fait donc n'importe quoi.
          Il a donc comme vous l'avez évoqué à la fin de votre réponse, mal interprété les différentes requêtes HTTP. Ce qui faut du coup régler car sinon le serveur est off :/.

          J'espère avoir été un peu plus clair, en vous souhaitant une bonne soirée, bien cordialement.

          EDIT :
          Rebonjour à vous. Je suis sur une très bonne piste ^^.
          En fait, le serveur arrive à recevoir les messages. Voici le message d'un client qui se connecte via le logiciel :
          [RPC SERVER]: A client is connected.
          "\x00\xF0\x00\x00\x00\xEC\x00{\x00\"\x00j\x00s\x00o\x00n\x00r\x00p\x00""c\x00\"\x00:\x00\"\x00""2\x00.\x00""0\x00\"\x00,\x00\"\x00m\x00""e\x00t\x00h\x00o\x00""d\x00\"\x00:\x00\"\x00s\x00u\x00""b\x00s\x00""c\x00r\x00i\x00""b\x00""e\x00\"\x00,\x00\"\x00p\x00""a\x00r\x00""a\x00m\x00s\x00\"\x00:\x00{\x00\"\x00""a\x00""d\x00""d\x00r\x00\"\x00:\x00\"\x00\"\x00,\x00\"\x00""a\x00""d\x00""d\x00r\x00l\x00o\x00""c\x00""a\x00l\x00\"\x00:\x00\"\x00""1\x00""9\x00""2\x00.\x00""1\x00""6\x00""8\x00.\x00""1\x00.\x00""8\x00""0\x00\"\x00,\x00\"\x00""b\x00l\x00o\x00""c\x00k\x00s\x00\"\x00:\x00""4\x00,\x00\"\x00p\x00""e\x00""e\x00r\x00\"\x00:\x00\"\x00n\x00o\x00""d\x00""e\x00\"\x00}\x00,\x00\"\x00i\x00""d\x00\"\x00:\x00""1\x00}"
          
          Et ça c'est le message lorsque je fais un curl.
          [RPC SERVER]: A client is connected.
          "GET / HTTP/1.1\r\nHost: localhost:27556\r\nUser-Agent: curl/7.55.1\r\nAccept: */*\r\n\r\n"
          Ici, j'avais directement fait un coup de socket->readAll(); ce qui n'est pas forcément la meilleure façon de faire d'autant plus que le message ne peut pas être reçu. Je vais donc aller voir quelque fonctions qui me seraient utiles. En attendant, je vous re merci de votre aide.

          Je cocherai résolu dès que le problème le sera.

          Bien cordialement.




          -
          Edité par Loopite 1 août 2021 à 11:17:49

          • Partager sur Facebook
          • Partager sur Twitter
            3 août 2021 à 12:02:29

            Comme ton code semble fortement inspiré d'un mauvais cours de réseau avec Qt, il copie plusieurs erreurs, à savoir:

            • il n'y a qu'une seule variable pour la taille du message pour tous les clients, donc le premier client qui y stocke une valeur, si jamais le message n'est pas reçu entièrement en une seule fois, va impacter tous les autres clients qui recevront des données en même temps. C'est ce qui se passe avec ton navigateur ou curl, les 2 premiers octets de "GET" sont lus dans la taille du message ("GE" => 0x4745 = 18245 ), et tous les clients qui se connectent voient que la variable heightPacket n'est pas nulle et attendent donc ces 18245 octets.
            • le flux TCP n'est pas, comme indiqué par bacelar, orienté message, donc à la fin d'un message, dans un même paquet TCP, il peut y avoir le début d'un message suivant, il faut donc recommencer la lecture après la réception d'un message entier.
            • depuis le cours, QDataStream a également évolué pour introduire les transactions, tu pourrais t'en servir au lieu de lire la taille du message dans une variable (et même, avec les transactions, envoyer et stocker la taille devient également inutile, puisque QString est déjà sérialisé avec sa taille suivie de son contenu).
            Par exemple, tu pourrais faire ça:
            void TCPServerController::receiveMessage()
            {
                QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
                if (socket == 0)
                    return;
                
                QDataStream in(socket);
                while(socket->bytesAvailable()) {        
                    in.startTransaction(); // début de transaction
                    
                    quint16 packetSize;
                    QString message;
                    in >> packetSize; 
                    in >> message;
                    // si une des lectures précédentes a échoué, commitTransaction
                    // va remettre le flux dans l'état qu'il avait au début de 
                    // la transaction et renvoyer false
                    if (!in.commitTransaction())
                        return;
                
                    qDebug() << "-->" << message;
            
                    parse(message, socket);
                }
            }

            Mais ça ne réglerait pas totalement le problème d'un client qui se connecterait avec le mauvais protocole, même s'il ne bloquerait plus les autres sockets, il garderait le socket ouvert jusqu'à ce que le logiciel client (curl, navigateur...) décide de se déconnecter. Pour éviter de garder inutilement ce socket ouvert, il faudrait par exemple que tes logiciels clients envoient une séquence arbitraire mais spécifique à ton logiciel au début de la connexion pour vérifier qu'ils utilisent bien le bon protocole (séquence écrite et lue avec QTcpSocket::write et read ou QDataStream::writeRawData et readRawData, sinon ça va bloquer de la même façon, puisque QDataStream << et >> écrivent et lisent la taille des QString ou QByteArray avant de lire leur contenu) comme ça si cette séquence n'est pas présente, le serveur peut déconnecter le client rapidement.

            • Partager sur Facebook
            • Partager sur Twitter
              4 août 2021 à 17:26:01

              Bonjour, merci de votre réponse alexisdm.

              Je tenais à vous remercier des informations que vous m'avez fournies.
              En ce qui concerne le problème du client qui ne se connecte pas avec le bon protocole, j'avais déjà élucidé ce problème, en envoyant directement un message lors de la connexion au serveur :lol:.
              En tout cas, merci beaucoup pour votre explication détaillée.

              Bien cordialement.
              • Partager sur Facebook
              • Partager sur Twitter

              QTcpServer

              × 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.
              • Editeur
              • Markdown