{"id":2545,"date":"2015-05-02T12:24:40","date_gmt":"2015-05-02T12:24:40","guid":{"rendered":"http:\/\/anthroponaute.fr\/blog-informatique\/?p=2545"},"modified":"2016-02-21T10:06:48","modified_gmt":"2016-02-21T10:06:48","slug":"introduction-a-la-programmation-reseau-sockets-partie-2","status":"publish","type":"post","link":"https:\/\/www.la-porte-des-nebuleuses.net\/blog-informatique\/?p=2545","title":{"rendered":"Introduction \u00e0 la programmation r\u00e9seau (Sockets) \u2013 partie 2"},"content":{"rendered":"<p><a href=\"https:\/\/anthropoya.cluster014.ovh.net\/blog-informatique\/wp-content\/uploads\/2015\/04\/484052892.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-2251\" src=\"https:\/\/anthropoya.cluster014.ovh.net\/blog-informatique\/wp-content\/uploads\/2015\/04\/484052892.jpg\" alt=\"48405289\" width=\"318\" height=\"239\" srcset=\"https:\/\/www.la-porte-des-nebuleuses.net\/blog-informatique\/wp-content\/uploads\/2015\/04\/484052892.jpg 318w, https:\/\/www.la-porte-des-nebuleuses.net\/blog-informatique\/wp-content\/uploads\/2015\/04\/484052892-300x225.jpg 300w\" sizes=\"(max-width: 318px) 100vw, 318px\" \/><\/a><\/p>\n<p><strong>Intro :<\/strong><\/p>\n<p>Pour concevoir un jeu vid\u00e9o multijoueur il vous faut utiliser dans le programme C++ des objets qu\u2019on appelle <strong>sockets<\/strong>.<\/p>\n<p>Ceci constitue la <strong>deuxi\u00e8me partie<\/strong> de l&rsquo;ensemble des articles concernant les sockets.<\/p>\n<p>Dans cette partie nous allons concevoir un <strong>petit chat\u00a0<\/strong>en entrant du texte dans la console c\u00f4t\u00e9 client et c\u00f4t\u00e9 serveur.<\/p>\n<p><strong>Pr\u00e9requis :<\/strong><\/p>\n<p>\u2013 Savoir un peu lire et \u00e9crire du C++<\/p>\n<p>\u2013 \u00catre sous Windows.<\/p>\n<p>&#8211; Avoir suivi la premi\u00e8re partie de ce tutoriel<\/p>\n<p><strong>Explications :<\/strong><\/p>\n<p><strong>1 &#8211;<\/strong> Tout d&rsquo;abord nous allons \u00e9crire un petit programme de chat par \u00e9crit \u00e0 travers les entr\u00e9es clavier de l&rsquo;utilisateur dans la console.<\/p>\n<p><strong>2 &#8211;<\/strong> En deuxi\u00e8me partie, j\u2019\u00e9num\u00e9rerais l&rsquo;ordre d&rsquo;appel des fonctions sockets selon le r\u00f4le du programme (client ou serveur).<\/p>\n<p>&nbsp;<\/p>\n<hr \/>\n<p>&nbsp;<\/p>\n<p><strong>1 &#8211;<\/strong> Petit chat client \/ serveur<\/p>\n<p>Voici le code du chat <strong>c\u00f4t\u00e9 client<\/strong> (ChatClient.cpp) :<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\/\/----------------------------------------------------\r\n\/\/ Auteur : Cl\u00e9ment Profit\r\n\/\/ Nom du fichier : ChatClient.cpp\r\n\/\/ Date de cr\u00e9ation : Avril 2015\r\n\/\/ Description : Une impl\u00e9mentation d'un client de chat\r\n\/\/----------------------------------------------------\r\n\r\n#include &lt;winsock2.h&gt;\r\n\r\n#include &lt;stdio.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;conio.h&gt;\r\n\r\n#define PORT 23\r\n\r\n\/\/ On lie la librairie des sockets Windows\r\n#pragma comment(lib, &quot;ws2_32.lib&quot;)\r\n\r\n\/\/ Structure utilis\u00e9e pour envoyer ces deux param\u00e8tres \u00e0 la fonction\r\n\/\/ thread ; \u00e9tant donn\u00e9 que l'on ne peut qu'envoyer qu'un seul\r\n\/\/ param\u00e8tre aux fonctions thread\r\nstruct ThreadParam\r\n{\r\n\u00a0\u00a0 \u00a0bool bQuit;\r\n\u00a0\u00a0 \u00a0int server_sock;\r\n};\r\n\r\n\/\/ Message \u00e0 envoyer au serveur\r\nstruct ChatMessage\r\n{\r\n\u00a0\u00a0 \u00a0\/\/ Soit c'est un message texte, soit c'est une requ\u00eate pour cloturer \/ quitter\r\n\u00a0\u00a0 \u00a0\/\/ la connexion\r\n\u00a0\u00a0 \u00a0enum MessageType {CHAT_MESSAGE, CHAT_QUIT};\r\n\r\n\u00a0\u00a0 \u00a0ChatMessage(MessageType message, char* information)\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0message_type = message;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0strcpy_s(sInfo, information);\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0ChatMessage() {};\r\n\r\n\u00a0\u00a0 \u00a0MessageType message_type;\r\n\r\n\u00a0\u00a0 \u00a0\/\/ On utilise un tableau de caract\u00e8res \u00e0 taille fixe\r\n\u00a0\u00a0 \u00a0\/\/ car on ne peut envoyer un pointeur char* sur une machine distante\r\n\u00a0\u00a0 \u00a0\/\/ (le pointeur \u00e9tant li\u00e9 uniquement \u00e0 la m\u00e9moire de la machine \u00e9mettrice)\r\n\u00a0\u00a0 \u00a0char sInfo[4096];\r\n};\r\n\r\n\/\/ Fonction pour obtenir une cha\u00eene de caract\u00e8res tapp\u00e9e\r\n\/\/ depuis le clavier de l'utilisateur\r\nchar* get_string_input()\r\n{\r\n\u00a0\u00a0\u00a0 char* message = new char[4096];\r\n\r\n\u00a0\u00a0 \u00a0\/\/ La fonction _getch() permet de tapper un caract\u00e8re\r\n\u00a0\u00a0 \u00a0\/\/ sans l'afficher dans la console\r\n\u00a0\u00a0 \u00a0char ch = _getch();\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\/\/ Si on tappe la touche entr\u00e9e on ne fait rien\r\n\u00a0\u00a0 \u00a0if (ch == 13)\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0return nullptr;\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0unsigned int length = 0;\r\n\r\n\u00a0\u00a0 \u00a0\/\/ On tappe un caract\u00e8re par tour de boucle\r\n\u00a0\u00a0 \u00a0while (ch != 13) \/\/ Le caract\u00e8re 13 est la touche entr\u00e9e\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0message[length] = ch;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0length++;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (length &gt; 4096)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0break;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ch = _getch();\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0\/\/ A la fin du message, on met un indicateur de fin de cha\u00eene de caract\u00e8re\r\n\u00a0\u00a0 \u00a0\/\/ pour finaliser la cha\u00eene\r\n\u00a0\u00a0 \u00a0message[length] = '&#92;&#48;';\r\n\r\n\u00a0\u00a0 \u00a0return message;\r\n}\r\n\r\n\/\/ Thread pour entrer des messages \u00e0 partir du clavier\r\nDWORD WINAPI get_console_message(LPVOID lpParameter)\r\n{\r\n\u00a0\u00a0 \u00a0\/\/ On fait un cast pour obtenir notre param\u00e8tre\r\n\u00a0\u00a0 \u00a0ThreadParam* param = (ThreadParam*)lpParameter;\r\n\r\n\u00a0\u00a0 \u00a0printf(&quot;Saisissez un message.\\n&quot;);\r\n\u00a0\u00a0 \u00a0char* sMessage = nullptr;\r\n\r\n\u00a0\u00a0 \u00a0\/\/ A chaque tour de boucle correspond un message tapp\u00e9\r\n\u00a0\u00a0 \u00a0while(true)\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On obtient le message tapp\u00e9\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0sMessage = get_string_input();\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (sMessage == nullptr)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0continue;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Si l'on tappe &quot;quit&quot;, le programme s'arr\u00eate\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (strcmp(sMessage, &quot;quit&quot;) == 0)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0printf(&quot;Au revoir !\\n&quot;);\u00a0\u00a0 \u00a0\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0system(&quot;pause&quot;);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On envoie un ChatMessage de sortie\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ pour indiquer d'arr\u00eater le programme de la machine\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ distante\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ChatMessage quitMessage(ChatMessage::CHAT_QUIT, &quot;&quot;);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0send(param-&gt;server_sock, (char*)&amp;quitMessage, sizeof(quitMessage), 0);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Nous for\u00e7ons aussi l'arr\u00eat de notre programme sur la machine locale\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0param-&gt;bQuit = true;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0break;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0};\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On envoie un ChatMessage de texte corresopodant \u00e0 celui tapp\u00e9\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ChatMessage chatMessage(ChatMessage::CHAT_MESSAGE, sMessage);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0send(param-&gt;server_sock, (char*)&amp;chatMessage, sizeof(ChatMessage), 0);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0printf(&quot;[Vous]# %s\\n&quot;, sMessage);\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0delete sMessage;\r\n\r\n\u00a0\u00a0 \u00a0return 0;\r\n}\r\n\r\n\/** Client **\/\r\nint main(void)\r\n{\r\n\u00a0\u00a0 \u00a0\/\/ Il faut appeler ces deux instructions avant toute\r\n\u00a0\u00a0 \u00a0\/\/ utilisation de socket\r\n\u00a0\u00a0 \u00a0WSADATA WSAData;\r\n\u00a0\u00a0 \u00a0int error = WSAStartup(MAKEWORD(2,2), &amp;WSAData);\r\n\u00a0\r\n\u00a0\u00a0 \u00a0\/\/ Voici nos structures de socket\r\n\u00a0\u00a0 \u00a0SOCKET sock;\r\n\u00a0\u00a0 \u00a0SOCKADDR_IN server_in;\r\n\r\n\u00a0\u00a0\u00a0 \/\/ Si les sockets Windows fonctionnent\r\n\u00a0\u00a0\u00a0 if (!error)\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Cr\u00e9ation de la socket\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0sock = socket(AF_INET, SOCK_STREAM, 0);\r\n\u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On passe en mode non bloqu\u00e9, c'est-\u00e0-dire que les fonctions recv() et send()\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ ne bloquent pas quand un message n'a pas \u00e9t\u00e9 envoy\u00e9 ou re\u00e7u\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0unsigned long mode = 1;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ioctlsocket(sock, FIONBIO, &amp;mode);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Configuration de la connexion\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On peut changer ici l'adresse d'un serveur non local\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0server_in.sin_addr.s_addr = inet_addr(&quot;127.0.0.1&quot;);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0server_in.sin_family = AF_INET;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0server_in.sin_port = htons(PORT);\r\n\u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0printf(&quot;Tentative de connexion au serveur (tappez exit pour quitter)...\\n&quot;);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On se connecte au serveur\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0error = connect(sock, (SOCKADDR*)&amp;server_in, sizeof(server_in));\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (error != SOCKET_ERROR)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0printf(&quot;Connection \u00e0 %s sur le port %d\\n&quot;, inet_ntoa(server_in.sin_addr), htons(server_in.sin_port));\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Structure de param\u00e8tre pour envoyer\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ plus d'une variable \u00e0 la fonction thread\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ThreadParam param;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0param.bQuit = false;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0param.server_sock = sock;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Cr\u00e9ation d'un thread pour effectuer la lecture d'un message ind\u00e9pendamment\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ de l'\u00e9coute par la fonction recv\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0CreateThread(nullptr, 0, &amp;get_console_message, (void*)&amp;param, 0, nullptr); \u00a0\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ChatMessage* message = nullptr;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Comme les packets r\u00e9seaux re\u00e7us peuvent \u00eatre de diff\u00e9rentes tailles\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ et qu'ils sont re\u00e7us par segments,\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ nous avons besoin d'un buffer secondaires pour lui ajouter\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ les segments par segments\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0int iTotalBytes = sizeof(ChatMessage);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0int iCurrentBytes = 0;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0char* buffer = new char[iTotalBytes];\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0char* pRecvBuffer = new char[iTotalBytes];\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0while (!param.bQuit)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On recoit des donn\u00e9es qui peuvent \u00eatre un segment\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0int iBytes = recv(sock, buffer, iTotalBytes, 0);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (iBytes != SOCKET_ERROR)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On rajoute le segment re\u00e7u dans le buffer \u00e0 chaque fois\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ que des donn\u00e9es ont \u00e9t\u00e9 re\u00e7ues plus haut\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0memcpy(pRecvBuffer + iCurrentBytes, buffer, iBytes);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0iCurrentBytes += iBytes;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ D\u00e8s qu'on a re\u00e7u le message au complet\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ c'est-\u00e0-dire d\u00e8s que la taille du buffer a atteint\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ la taille du message\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (iCurrentBytes &gt;= iTotalBytes)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0message = (ChatMessage*) pRecvBuffer;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Si l'on recoit un message qui nous indique de quitter\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (message-&gt;message_type == ChatMessage::CHAT_QUIT)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0wprintf(L&quot;Le serveur s'est deconnect\u00e9.\\n&quot;);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0system(&quot;pause&quot;);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On quitte la boucle\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0break;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (message-&gt;sInfo != '&#92;&#48;')\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On affiche le message re\u00e7u depuis le serveur\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0printf(&quot;[Serveur]# : %s\\n&quot;, message-&gt;sInfo);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\u00a0\u00a0 \u00a0\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0iCurrentBytes = 0;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ On ferme la socket\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 closesocket(sock);\r\n\u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Termine l'utilisation de Winsock 2\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 WSACleanup();\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 return EXIT_SUCCESS;\r\n}\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Voici le code du chat<strong> c\u00f4t\u00e9 serveur<\/strong> (ChatServeur.cpp) :<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\/\/----------------------------------------------------\r\n\/\/ Auteur : Cl\u00e9ment Profit\r\n\/\/ Nom du fichier : ChatServeur.cpp\r\n\/\/ Date de cr\u00e9ation : Avril 2015\r\n\/\/ Description : Une impl\u00e9mentation d'un serveur de chat\r\n\/\/----------------------------------------------------\r\n\r\n#include &lt;winsock2.h&gt;\r\n#include &lt;stdio.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;string.h&gt;\r\n#include &lt;conio.h&gt;\r\n\r\n#define PORT 23\r\n\r\n\/\/ On lie la librairie des sockets Windows\r\n#pragma comment(lib, &quot;ws2_32.lib&quot;)\r\n\r\n\/\/ Structure utilis\u00e9e pour envoyer ces deux param\u00e8tres \u00e0 la fonction\r\n\/\/ thread ; \u00e9tant donn\u00e9 que l'on ne peut qu'envoyer qu'un seul\r\n\/\/ param\u00e8tre aux fonctions thread\r\nstruct ThreadParam\r\n{\r\n\u00a0\u00a0 \u00a0bool bQuit;\r\n\u00a0\u00a0 \u00a0int client_sock;\r\n};\r\n\r\n\/\/ Message \u00e0 envoyer au serveur\r\nstruct ChatMessage\r\n{\r\n\u00a0\u00a0 \u00a0\/\/ Soit c'est un message texte, soit c'est une requ\u00eate pour cloturer \/ quitter\r\n\u00a0\u00a0 \u00a0\/\/ la connexion\r\n\u00a0\u00a0 \u00a0enum MessageType {CHAT_MESSAGE, CHAT_QUIT};\r\n\r\n\u00a0\u00a0 \u00a0ChatMessage(MessageType message, char* information)\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0message_type = message;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0strcpy_s(sInfo, information);\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0ChatMessage() {};\r\n\r\n\u00a0\u00a0 \u00a0MessageType message_type;\r\n\r\n\u00a0\u00a0 \u00a0\/\/ On utilise un tableau de caract\u00e8res \u00e0 taille fixe\r\n\u00a0\u00a0 \u00a0\/\/ car on ne peut envoyer un pointeur char* sur une machine distante\r\n\u00a0\u00a0 \u00a0\/\/ (le pointeur \u00e9tant li\u00e9 uniquement \u00e0 la m\u00e9moire de la machine \u00e9mettrice)\r\n\u00a0\u00a0 \u00a0char sInfo[4096];\r\n};\r\n\r\n\/\/ Si un erreur a lieu, on affiche la raison\r\n\/\/ puis on quitte\r\nvoid exit_on_fail(int sock_err)\r\n{\r\n\u00a0\u00a0 \u00a0if (sock_err == SOCKET_ERROR)\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0printf(&quot;Socket Error Code = %i&quot;, WSAGetLastError());\r\n\u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0system(&quot;pause&quot;);\r\n\u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0exit(EXIT_FAILURE);\r\n\u00a0\u00a0 \u00a0}\r\n}\r\n\r\n\/\/ Fonction pour obtenir une cha\u00eene de caract\u00e8res tapp\u00e9e\r\n\/\/ depuis le clavier de l'utilisateur\r\nchar* get_string_input()\r\n{\r\n\u00a0\u00a0\u00a0 char* message = new char[4096];\r\n\r\n\u00a0\u00a0 \u00a0\/\/ La fonction _getch() permet de tapper un caract\u00e8re\r\n\u00a0\u00a0 \u00a0\/\/ sans l'afficher dans la console\r\n\u00a0\u00a0 \u00a0char ch = _getch();\r\n\r\n\u00a0\u00a0 \u00a0\/\/ Si on tappe la touche entr\u00e9e on ne fait rien\r\n\u00a0\u00a0 \u00a0if (ch == 13)\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0return nullptr;\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0unsigned int length = 0;\r\n\r\n\u00a0\u00a0 \u00a0\/\/ On tappe un caract\u00e8re par tour de boucle\r\n\u00a0\u00a0 \u00a0while (ch != 13) \/\/ Le caract\u00e8re 13 est la touche entr\u00e9e\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0message[length] = ch;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0length++;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (length &gt; 4096)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0break;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ch = _getch();\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0\/\/ A la fin du message, on met un indicateur de fin de cha\u00eene de caract\u00e8re\r\n\u00a0\u00a0 \u00a0\/\/ pour finaliser la cha\u00eene\r\n\u00a0\u00a0 \u00a0message[length] = '&#92;&#48;';\r\n\r\n\u00a0\u00a0 \u00a0return message;\r\n}\r\n\r\n\/\/ Thread pour entrer des messages \u00e0 partir du clavier\r\nDWORD WINAPI get_console_message(LPVOID lpParameter)\r\n{\r\n\u00a0\u00a0 \u00a0\/\/ On fait un cast pour obtenir notre param\u00e8tre\r\n\u00a0\u00a0 \u00a0ThreadParam* param = (ThreadParam*)lpParameter;\r\n\r\n\u00a0\u00a0 \u00a0printf(&quot;Saisissez un message.\\n&quot;);\r\n\u00a0\u00a0 \u00a0char* sMessage = nullptr;\r\n\r\n\u00a0\u00a0 \u00a0\/\/ A chaque tour de boucle correspond un message tapp\u00e9\r\n\u00a0\u00a0 \u00a0while(true)\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On obtient le message tapp\u00e9\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0sMessage = get_string_input();\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (sMessage == nullptr)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0continue;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Si l'on tappe &quot;exit&quot;, le programme s'arr\u00eate\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (strcmp(sMessage, &quot;quit&quot;) == 0)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0printf(&quot;Au revoir !\\n&quot;);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0system(&quot;pause&quot;);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On envoie un ChatMessage de sortie\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ pour indiquer d'arr\u00eater le programme de la machine\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ChatMessage quitMessage(ChatMessage::CHAT_QUIT, &quot;&quot;);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0send(param-&gt;client_sock, (char*)&amp;quitMessage, sizeof(ChatMessage), 0);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Nous for\u00e7ons aussi l'arr\u00eat de notre programme sur la machine locale\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0param-&gt;bQuit = true;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0break;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0};\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On envoie un ChatMessage de texte correspondant \u00e0 celui tapp\u00e9\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ChatMessage chatMessage(ChatMessage::CHAT_MESSAGE, sMessage);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0send(param-&gt;client_sock, (char*)&amp;chatMessage, sizeof(ChatMessage), 0);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0printf(&quot;[Vous]# %s\\n&quot;, sMessage);\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0delete sMessage;\r\n\r\n\u00a0\u00a0 \u00a0return 0;\r\n}\r\n\r\n\/** Serveur **\/\r\nint main(void)\r\n{\r\n\u00a0\u00a0 \u00a0\/\/ Il faut appeler ces deux instructions avant toute\r\n\u00a0\u00a0 \u00a0\/\/ utilisation de socket\r\n\u00a0\u00a0 \u00a0WSADATA WSAData;\r\n\u00a0\u00a0 \u00a0int error = WSAStartup(MAKEWORD(2,2), &amp;WSAData);\r\n\r\n\u00a0\u00a0\u00a0 SOCKET sock;\r\n\u00a0\u00a0 \u00a0SOCKET client_sock;\r\n\r\n\u00a0\u00a0 \u00a0\/\/ Voici nos structures de socket\r\n\u00a0\u00a0\u00a0 SOCKADDR_IN server_in;\r\n\u00a0\u00a0\u00a0 SOCKADDR_IN client_in;\r\n\r\n\u00a0\u00a0\u00a0 int recsize = sizeof(client_in);\r\n\r\n\u00a0\u00a0\u00a0 int sock_err;\r\n\u00a0\r\n\u00a0\u00a0\u00a0 \/\/ Si les sockets Windows fonctionnent\r\n\u00a0\u00a0\u00a0 if (!error)\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Cr\u00e9ation de la socket\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sock = socket(AF_INET, SOCK_STREAM, 0);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On passe en mode non bloqu\u00e9, c'est-\u00e0-dire que les fonctions recv() et send()\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ ne bloquent pas quand un message n'a pas \u00e9t\u00e9 envoy\u00e9 ou re\u00e7u\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0unsigned long mode = 1;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ioctlsocket(sock, FIONBIO, &amp;mode);\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Si la socket est valide\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (sock != INVALID_SOCKET)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 printf(&quot;Bienvenu sur le chat (tappez exit pour quitter) !\\n\\nLe serveur est maintenant ouvert en mode TCP\/IP sur le port %d\\n\\n&quot;, PORT);\r\n\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Configuration de la socket\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 server_in.sin_addr.s_addr = htonl(INADDR_ANY);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 server_in.sin_family = AF_INET;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 server_in.sin_port = htons(PORT); \r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On configure le serveur\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sock_err = bind(sock, (SOCKADDR*)&amp;server_in, sizeof(server_in));\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0exit_on_fail(sock_err);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0sock_err = listen(sock, 5);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0exit_on_fail(sock_err);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0printf(&quot;Patientez pendant que le client se connecte...\\n&quot;);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On boucle pour attendre la connexion d'un client\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0while (true)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0client_sock = accept(sock, (SOCKADDR*)&amp;client_in, &amp;recsize);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Si un client se connecte\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (client_sock != SOCKET_ERROR)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0printf(&quot;\\nUn client se connecte avec la socket %d de %s:%d\\n&quot;, client_sock, inet_ntoa(client_in.sin_addr), htons(client_in.sin_port));\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0break;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Structure de param\u00e8tre pour envoyer\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ plus d'une variable \u00e0 la fonction thread\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ThreadParam param;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0param.bQuit = false;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0param.client_sock = client_sock;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Cr\u00e9ation d'un thread pour effectuer la lecture d'un message ind\u00e9pendamment\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ de l'\u00e9coute de la socket\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0CreateThread(nullptr, 0, &amp;get_console_message, (void*)&amp;param, 0, nullptr);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ChatMessage* message = nullptr;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Comme les packets r\u00e9seaux re\u00e7us peuvent \u00eatre de diff\u00e9rentes tailles\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ et qu'ils sont re\u00e7us par segments,\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ nous avons besoin d'un buffer secondaires pour lui ajouter\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ les segments par segments\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0int iTotalBytes = sizeof(ChatMessage);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0int iCurrentBytes = 0;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0char* buffer = new char[iTotalBytes];\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0char* pRecvBuffer = new char[iTotalBytes];\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0while (!param.bQuit)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On recoit des donn\u00e9es qui peuvent \u00eatre un segment\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0int iBytes = recv(client_sock, buffer, iTotalBytes, 0);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (iBytes != SOCKET_ERROR)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On rajoute le segment re\u00e7u dans le buffer \u00e0 chaque fois\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ que des donn\u00e9es ont \u00e9t\u00e9 re\u00e7ues plus haut\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0memcpy(pRecvBuffer + iCurrentBytes, buffer, iBytes);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0iCurrentBytes += iBytes;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ D\u00e8s qu'on a re\u00e7u le message au complet\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ c'est-\u00e0-dire d\u00e8s que la taille du buffer a atteint\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ la taille du message\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (iCurrentBytes &gt;= iTotalBytes)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0message = (ChatMessage*) pRecvBuffer;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Si l'on recoit un message qui nous indique de quitter\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (message-&gt;message_type == ChatMessage::CHAT_QUIT)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0wprintf(L&quot;Le client s'est deconnect\u00e9.\\n&quot;);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0system(&quot;pause&quot;);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On quitte la boucle\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0break;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (message-&gt;sInfo != '&#92;&#48;')\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On affiche le message re\u00e7u depuis le client\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0printf(&quot;[Client]# : %s\\n&quot;, message-&gt;sInfo);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0iCurrentBytes = 0;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ On ferme la socket\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0closesocket(sock);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 WSACleanup();\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\r\n\u00a0\u00a0\u00a0 return EXIT_SUCCESS;\r\n}\r\n<\/pre>\n<p>&nbsp;<\/p>\n<hr \/>\n<p>&nbsp;<\/p>\n<p><strong>2 &#8211; Ordre d&rsquo;appel<\/strong> des fonctions socket selon le r\u00f4le de l&rsquo;application (client ou serveur) :<\/p>\n<p><a href=\"https:\/\/anthropoya.cluster014.ovh.net\/blog-informatique\/wp-content\/uploads\/2015\/05\/OrdreTCP1.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-2821\" src=\"https:\/\/anthropoya.cluster014.ovh.net\/blog-informatique\/wp-content\/uploads\/2015\/05\/OrdreTCP1.png\" alt=\"OrdreTCP\" width=\"445\" height=\"604\" srcset=\"https:\/\/www.la-porte-des-nebuleuses.net\/blog-informatique\/wp-content\/uploads\/2015\/05\/OrdreTCP1.png 445w, https:\/\/www.la-porte-des-nebuleuses.net\/blog-informatique\/wp-content\/uploads\/2015\/05\/OrdreTCP1-221x300.png 221w\" sizes=\"(max-width: 445px) 100vw, 445px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p><strong>R\u00e9sum\u00e9 :<\/strong><\/p>\n<p>Nous avons construit une application client \/ serveur pour communiquer en messagerie par le biais de la fen\u00eatre console.<\/p>\n<p><strong>R\u00e9f\u00e9rences :<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Intro : Pour concevoir un jeu vid\u00e9o multijoueur il vous faut utiliser dans le programme C++ des objets qu\u2019on appelle sockets. Ceci constitue la deuxi\u00e8me partie de l&rsquo;ensemble des articles concernant les sockets. Dans cette partie nous allons concevoir un petit chat\u00a0en entrant du texte dans la console c\u00f4t\u00e9 client et c\u00f4t\u00e9 serveur. Pr\u00e9requis : [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[22],"tags":[],"_links":{"self":[{"href":"https:\/\/www.la-porte-des-nebuleuses.net\/blog-informatique\/index.php?rest_route=\/wp\/v2\/posts\/2545"}],"collection":[{"href":"https:\/\/www.la-porte-des-nebuleuses.net\/blog-informatique\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.la-porte-des-nebuleuses.net\/blog-informatique\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.la-porte-des-nebuleuses.net\/blog-informatique\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.la-porte-des-nebuleuses.net\/blog-informatique\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2545"}],"version-history":[{"count":17,"href":"https:\/\/www.la-porte-des-nebuleuses.net\/blog-informatique\/index.php?rest_route=\/wp\/v2\/posts\/2545\/revisions"}],"predecessor-version":[{"id":2822,"href":"https:\/\/www.la-porte-des-nebuleuses.net\/blog-informatique\/index.php?rest_route=\/wp\/v2\/posts\/2545\/revisions\/2822"}],"wp:attachment":[{"href":"https:\/\/www.la-porte-des-nebuleuses.net\/blog-informatique\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2545"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.la-porte-des-nebuleuses.net\/blog-informatique\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2545"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.la-porte-des-nebuleuses.net\/blog-informatique\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2545"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}