{"id":169,"date":"2017-02-04T12:21:14","date_gmt":"2017-02-04T12:21:14","guid":{"rendered":"http:\/\/renaudguezennec.eu\/?p=169"},"modified":"2025-08-17T20:12:07","modified_gmt":"2025-08-17T20:12:07","slug":"creer-un-webservice-en-c-avec-qt","status":"publish","type":"post","link":"http:\/\/renaudguezennec.eu\/index.php\/2017\/02\/04\/creer-un-webservice-en-c-avec-qt\/","title":{"rendered":"Cr\u00e9er un WebService en C++ avec Qt"},"content":{"rendered":"<p>Un petit article pour \u00e9voquer la possibilit\u00e9 de faire un webservice, en C++\/Qt.<\/p>\n<p>Mon besoin est simple, je veux fournir une interface web pour r\u00e9aliser des lancer de d\u00e9s avec le syst\u00e8me de lancement de d\u00e9s <strong>DiceParser<\/strong>, issu de <strong>Rolisteam<\/strong>.<\/p>\n<p><strong>DiceParser<\/strong> est \u00e9crit en C++ avec Qt5. A partir de ce constat, je pouvais soit faire un serveur web en C++, soit faire un site web en python\/php\/whatever pour lancer une commande syst\u00e8me et utiliser dice, le client en ligne de commande de <strong>DiceParser<\/strong>.<\/p>\n<p>La deuxi\u00e8me solution est\u00a0 la plus facile mais clairement un peu \u00absale\u00bb et niveau s\u00e9curit\u00e9 ce n\u2019est pas id\u00e9al. Le \u00abchallenge\u00bb se trouve dans la premi\u00e8re m\u00e9thode.<br \/>\nJe n&#8217;avais pas envie de r\u00e9inventer la roue donc j&#8217;ai cherch\u00e9 une solution technique pour satisfaire mon besoin. Un composant C++\/Qt qui permet de cr\u00e9er un serveur http avec possibilit\u00e9 d&#8217;\u00eatre notifier \u00e0 chaque requ\u00eate. J&#8217;ai trouv\u00e9 un composant qui r\u00e9alise cela.<\/p>\n<p>Le d\u00e9p\u00f4t git du composant : https:\/\/github.com\/azadkuh\/qhttp.git<\/p>\n<h2>Impl\u00e9mentation du serveur<\/h2>\n<p>[pastacode lang=&#8221;cpp&#8221; manual=&#8221;%20%20m_server%20%3D%20new%20qhttp%3A%3Aserver%3A%3AQHttpServer(this)%3B%0A%20%20%20%20m_server-%3Elisten(%20%2F%2F%20listening%20on%200.0.0.0%3A8080%0A%20%20%20%20%20%20%20%20%20%20%20%20QHostAddress%3A%3AAny%2C%20port%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B%3D%5D(qhttp%3A%3Aserver%3A%3AQHttpRequest*%20req%2C%20qhttp%3A%3Aserver%3A%3AQHttpResponse*%20res)%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20req-%3EcollectData(1024)%3B%0A%0A%09%09%2F%2F%20Ici%20mettre%20le%20code%20d&#8217;analyse%20de%20la%20requ%C3%AAte%0A%0A%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20if%20(%20!m_server-%3EisListening()%20)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20qDebug()%20%3C%3C%20%22failed%20to%20listen%22%3B%0A%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20else%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20qDebug()%3C%3C%20%22Server%20is%20On!!%22%3B%0A%20%20%20%20%7D&#8221; message=&#8221;Instancier le serveur web&#8221; highlight=&#8221;&#8221; provider=&#8221;manual&#8221;\/]<\/p>\n<p>Nous cr\u00e9ons une instance du serveur, nous d\u00e9marrons l&#8217;\u00e9coute sur le port (80 par d\u00e9faut pour le protocole http).<br \/>\nL&#8217;\u00e9coute est r\u00e9alis\u00e9 par une fonction lambda, cela n&#8217;a rien d&#8217;obligatoire, mais c&#8217;est plus minimaliste.<\/p>\n<p>Notre fonction est notifi\u00e9e \u00e0 la r\u00e9ception d&#8217;une requ\u00eate http.<\/p>\n<h2>R\u00e9cup\u00e9rer les informations d&#8217;une requ\u00eate<\/h2>\n<p>[pastacode lang=&#8221;cpp&#8221; manual=&#8221;%2F%2F%20R%C3%A9cup%C3%A8re%20les%20donn%C3%A9es%0Areq-%3EcollectData(1024)%3B%0A%0A%2F%2F%20R%C3%A9cup%C3%A8re%20l&#8217;url%20(les%20donn%C3%A9es%20du%20GET)%0AQString%20getArg%20%3D%20req-%3Eurl().toString()%3B%0A%0A%2F%2F%20D%C3%A9coupage%20des%20arguments%0AgetArg%3DgetArg.replace(%22%2F%3F%22%2C%22%22)%3B%0AQStringList%20args%20%3D%20getArg.split(&#8216;%26&#8217;)%3B%0AQHash%3CQString%2CQString%3E%20m_hashArgs%3B%0Afor(%20auto%20argument%20%3A%20args)%0A%7B%0A%20%20%20%20QStringList%20keyValue%20%3D%20argument.split(&#8216;%3D&#8217;)%3B%0A%20%20%20%20if(keyValue.size()%3D%3D2)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20m_hashArgs.insert(keyValue%5B0%5D%2CkeyValue%5B1%5D)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2F%20recherche%20dans%20la%20table%20des%20arguments%20la%20pr%C3%A9sence%20de%20fonction.%0Aif(m_hashArgs.contains(%22cmd%22))%0A%7B%0A%09%2F%2F%20r%C3%A9pondre%20%C3%A0%20la%20requ%C3%AAte%20reconnue.%0A%7D&#8221; message=&#8221;D\u00e9coupage&#8221; highlight=&#8221;&#8221; provider=&#8221;manual&#8221;\/]<\/p>\n<p>Ici, nous analysons la requ\u00eate pour identifier les actions \u00e0 r\u00e9aliser. Nous cherchons le param\u00e8tre cmd, pour trouver la commander \u00e0 identifier. Le travail pr\u00e9alable est des cr\u00e9er une tableau associatif (dans une QHash) pour conserver les param\u00e8tres et leur valeur.<\/p>\n<p>Une fois la commande de d\u00e9s identifi\u00e9s, il faut l&#8217;ex\u00e9cuter.<\/p>\n<h2>Ex\u00e9cuter la commande et r\u00e9pondre<\/h2>\n<p>[pastacode lang=&#8221;cpp&#8221; manual=&#8221;%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20QString%20result%20%3D%20startDiceParsing(QUrl%3A%3AfromPercentEncoding(m_hashArgs%5B%22cmd%22%5D.toLocal8Bit()))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20res-%3EsetStatusCode(qhttp%3A%3AESTATUS_OK)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20res-%3EaddHeader(%22Access-Control-Allow-Origin%22%2C%20%22*%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20res-%3EaddHeader(%22Access-Control-Allow-Methods%22%2C%20%22POST%2C%20GET%2C%20OPTIONS%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20res-%3EaddHeader(%22Access-Control-Allow-Headers%22%2C%20%22x-requested-with%22)%3B%0A%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20QString%20html(%22%3C!doctype%20html%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%3Chtml%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%3Chead%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%20%20%3Cmeta%20charset%3D%5C%22utf-8%5C%22%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%20%20%3Ctitle%3ERolisteam%20Dice%20System%20Webservice%3C%2Ftitle%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%20%20%3Cstyle%3E.dice%20%7Bcolor%3A%23FF0000%3Bfont-weight%3A%20bold%3B%7D%3C%2Fstyle%3E%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%3C%2Fhead%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cbody%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%251%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%3C%2Fbody%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%3C%2Fhtml%3E%5Cn%22)%3B%0A%0Ares-%3Eend(html.arg(result).toLocal8Bit())%3B&#8221; message=&#8221;&#8221; highlight=&#8221;&#8221; provider=&#8221;manual&#8221;\/]<\/p>\n<p>La premi\u00e8re action est de convertir la commande pour la transformer en donn\u00e9es lisibles. Elle est actuellement encod\u00e9 en mode pourcent. Qt fournit une m\u00e9thode statique pour faire la conversion. Le resultat de cette conversion est ensuite envoy\u00e9 \u00e0 une fonction qui ex\u00e9cute la commande et donne le r\u00e9sultat.<\/p>\n<p>Il faut ensuite g\u00e9n\u00e9rer la r\u00e9ponse. Le premier truc \u00e0 d\u00e9finir est le code r\u00e9ponse du protocole http. Le module qhttp propose des raccourcis pour cela.<\/p>\n<p>Ensuite, la r\u00e9ponse doit contenir 3 param\u00e8tres dans les headers afin d&#8217;\u00eatre accessible par des frameworks Ajax\/javascript\/Web 2.0 (vous ressentez mon d\u00e9dain envers ces techno ?).<br \/>\nApr\u00e8s la d\u00e9finition des headers, il faut cr\u00e9er le code html (ou autre) de la r\u00e9ponse.<\/p>\n<h2>Cr\u00e9er une page web cliente du service<\/h2>\n<p>[pastacode lang=&#8221;markup&#8221; manual=&#8221;%3C!DOCTYPE%20html%3E%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%3Chtml%3E%20%20%20%20%20%20%0A%3Chead%3E%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%3Cmeta%20charset%3D%22utf-8%22%3E%20%0A%3Cmeta%20name%3D%22Author%22%20content%3D%22Renaud%20GUEZENNEC%22%2F%3E%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%3Ctitle%3ERolisteam%20Dice%20System%20Webservice%3C%2Ftitle%3E%20%20%0A%20%20%3Cstyle%3E.dice%20%7Bcolor%3A%23FF0000%3Bfont-weight%3A%20bold%3B%7D%3C%2Fstyle%3E%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%3Cscript%20type%3D%22text%2Fjavascript%22%20src%3D%22js%2Fjquery-3.1.1.min.js%22%20%3E%3C%2Fscript%3E%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%3Cscript%20type%3D%22text%2Fjavascript%22%3E%20%20%0A%20%20%20%20function%20displayResult()%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20var%20request%20%3D%20%24.ajax(%7B%20%20%20%0A%20%20%20%20%20%20%20%20method%3A%20%22get%22%2C%20%20%20%20%0A%20%20%20%20%20%20%20%20url%3A%20%22http%3A%2F%2F127.0.0.1%3A8085%2F%22%2C%20%20%0A%20%20%20%20%20%20%20%20dataType%3A%20%22html%22%2C%20%20%0A%20%20%20%20%20%20%20%20async%3A%20false%2C%0A%20%20%20%20%20%20%20%20data%3A%20%7Bcmd%3A%20%24(&#8216;%23cmd&#8217;).val()%7D%20%0A%20%20%20%20%20%20%7D)%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20request.done(function(data)%7B%20%20%0A%20%20%20%20%20%20%20%20var%20str%20%3D%22%3Cp%3E%22%20%0A%20%20%20%20%20%20%20%20str%20%3D%20str.concat(data%2C%22%3C%2Fp%3E%22)%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%24(&#8216;.diceresult&#8217;).prepend(str)%3B%20%20%20%20%0A%20%20%20%20%20%20%7D)%3B%20%0A%20%20%20%20%7D%20%20%20%0A%20%20%3C%2Fscript%3E%20%20%0A%3C%2Fhead%3E%20%20%20%20%20%20%20%0A%3Cbody%3E%20%20%20%20%0A%3Cform%20method%3D%22POST%22%20action%3D%22%22%2F%3E%20%0A%3Cinput%20id%3D%22cmd%22%20name%3D%22cmd%22%2F%3E%20%20%0A%3Cinput%20id%3D%22roll%22%20name%3D%22roll%22%20type%3D%22button%22%20onclick%3D%22javascript%3AdisplayResult()%3B%20return%200%3B%22%20value%3D%22Roll%22%2F%3E%0A%3C%2Fform%3E%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%3Ca%20href%3D%22index.html%22%3EClear%3C%2Fa%3E%20%0A%3Cdiv%20class%3D%22diceresult%22%3E%0A%3C%2Fdiv%3E%20%20%20%20%20%20%0A%3C%2Fbody%3E%20%0A%3C%2Fhtml%3E&#8221; message=&#8221;Page cliente&#8221; highlight=&#8221;&#8221; provider=&#8221;manual&#8221;\/]<\/p>\n<p>Le travail ici est assez simple. Il faut cr\u00e9er un formulaire pour permettre \u00e0 l&#8217;utilisateur de saisir la commande de d\u00e9s. J&#8217;ai utilis\u00e9 JQuery comme framework javascript pour r\u00e9cup\u00e9rer la commande et envoyer la requ\u00eate de mon <strong>webservice<\/strong>. Quand la requ\u00eate s&#8217;est bien pass\u00e9e, le r\u00e9sultat s&#8217;affiche dans la page sans recharger la page.<\/p>\n<p>Le lien vers le code source: https:\/\/github.com\/Rolisteam\/DiceParser\/tree\/master\/webserver<br \/>\nLe webservice fait partie de projet <strong>DiceParser<\/strong>: https:\/\/github.com\/Rolisteam\/DiceParser<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Un petit article pour \u00e9voquer la possibilit\u00e9 de faire un webservice, en C++\/Qt. Mon besoin est simple, je veux fournir une interface web pour r\u00e9aliser des lancer de d\u00e9s avec le syst\u00e8me de lancement de d\u00e9s DiceParser, issu de Rolisteam. DiceParser est \u00e9crit en C++ avec Qt5. A partir de ce constat, je pouvais soit [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":178,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_import_markdown_pro_load_document_selector":0,"_import_markdown_pro_submit_text_textarea":"","footnotes":""},"categories":[80,23],"tags":[46,36,44,45],"class_list":["post-169","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-fr","category-tutorial","tag-diceparser","tag-qt5","tag-webserver","tag-webservice"],"_links":{"self":[{"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/posts\/169","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/comments?post=169"}],"version-history":[{"count":5,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/posts\/169\/revisions"}],"predecessor-version":[{"id":1310,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/posts\/169\/revisions\/1310"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/media\/178"}],"wp:attachment":[{"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/media?parent=169"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/categories?post=169"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/tags?post=169"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}