Programmation réseau en C++ : des sockets à l'asynchrone
\n\nVous êtes-vous déjà demandé comment fonctionnent les chats, les jeux en ligne ou les serveurs web ? Au cœur de chacun d'eux se trouve la communication réseau. Et si vous voulez écrire des applications réseau rapides, fiables et de bas niveau, la programmation réseau en C++ est ce qu'il vous faut. Dans cet article, nous n'allons pas simplement survoler la théorie, nous allons écrire du vrai code : d'un simple chat TCP à un serveur asynchrone avec Boost.Asio. Préparez vos IDE, ça va être intéressant !
\n\nPourquoi le C++ pour le réseau ? Trois raisons
\nBeaucoup choisissent Python ou Java pour les tâches réseau, mais le C++ offre trois avantages clés :
\n- \n
- Vitesse : Frais généraux minimaux, accès direct aux appels système (syscalls). \n
- Contrôle : Vous gérez manuellement la mémoire, les tampons et les temporisations. \n
- Écosystème :
Boost.Asio,libcurl,Poco— des bibliothèques puissantes pour toutes les tâches. \n
Mais un grand pouvoir implique de grandes responsabilités : une seule erreur dans la gestion d'un socket et votre serveur s'effondre. Voyons comment éviter cela.
\n\nLes bases : sockets et modèle OSI
\nAvant d'écrire du code, rappelons ce qu'est un socket. C'est une abstraction qui permet à une application d'envoyer et de recevoir des données sur le réseau. En C++, on travaille avec sys/socket.h (Linux) ou winsock2.h (Windows).
TCP vs UDP : quand utiliser quoi ?
\n- \n
- TCP (SOCK_STREAM) : Garantit la livraison et l'ordre des paquets. Idéal pour les chats, HTTP, les bases de données. \n
- UDP (SOCK_DGRAM) : Plus rapide, mais sans garantie. Utilisé dans le streaming, le DNS, les jeux en ligne (où perdre un paquet est moins grave qu'un délai). \n
Écrire un serveur et un client TCP en C++ (sockets purs)
\nCréons un serveur d'écho très simple. Il reçoit un message et le renvoie. C'est le classique « Hello, World » de la programmation réseau en C++.
\n\nPartie serveur (echo_server.cpp)
\n#include <iostream>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <unistd.h>\n#include <cstring>\n\nint main() {\n int server_fd, client_fd;\n struct sockaddr_in address;\n int opt = 1;\n int addrlen = sizeof(address);\n char buffer[1024] = {0};\n\n // 1. Création du socket\n if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {\n perror("socket failed");\n exit(EXIT_FAILURE);\n }\n\n // 2. Liaison au port (option reuse port)\n if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {\n perror("setsockopt");\n exit(EXIT_FAILURE);\n }\n address.sin_family = AF_INET;\n address.sin_addr.s_addr = INADDR_ANY;\n address.sin_port = htons(8080);\n\n if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {\n perror("bind failed");\n exit(EXIT_FAILURE);\n }\n\n // 3. Écoute des connexions entrantes\n if (listen(server_fd, 3) < 0) {\n perror("listen");\n exit(EXIT_FAILURE);\n }\n\n std::cout << "Serveur démarré sur le port 8080. En attente de connexions..." << std::endl;\n\n // 4. Acceptation du client\n if ((client_fd = accept(server_fd, (struct sockaddr *)&address,\n (socklen_t*)&addrlen)) < 0) {\n perror("accept");\n exit(EXIT_FAILURE);\n }\n\n // 5. Lecture et renvoi (écho)\n int valread = read(client_fd, buffer, 1024);\n std::cout << "Reçu : " << buffer << std::endl;\n send(client_fd, buffer, strlen(buffer), 0);\n std::cout << "Réponse d'écho envoyée" << std::endl;\n\n close(client_fd);\n close(server_fd);\n return 0;\n}\n\nPartie client (echo_client.cpp)
\n#include <