0Pricing
C Academy · Leçon

Un serveur d’écho simple

Servez plusieurs clients simultanément.

Un serveur d’écho simple est une leçon C Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C Academy comprend 4 leçons au total.

Ce que nous allons construire

Un serveur d’écho accepte les connexions TCP et renvoie les octets envoyés par un client. C’est le « hello world » de la programmation réseau.

Nous allons le construire avec epoll afin qu’un seul thread serve de nombreux clients simultanément. Les éléments sont les suivants : une socket d’écoute, la boucle epoll et la gestion lecture puis écriture de chaque client.

Créer la socket d’écoute

Commencez par socket() pour créer un point de terminaison TCP IPv4. Le triplet est AF_INET, SOCK_STREAM et le protocole 0.

Cela renvoie un descripteur de fichier que nous associerons à une adresse, configurerons en mode non bloquant, puis enregistrerons auprès d’epoll. Vérifiez la valeur -1 après chaque appel système.

int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd == -1) { perror("socket"); exit(1); }

Réutiliser l’adresse

Avant l’association à une adresse, définissez SO_REUSEADDR avec setsockopt(). Le serveur pourra ainsi redémarrer et réutiliser le même port sans attendre la fin de l’état TIME_WAIT.

Sans cette option, un redémarrage rapide échoue souvent avec EADDRINUSE, ce qui est particulièrement frustrant pendant le développement.

int yes = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);

Associer une socket à un port

Remplissez une struct sockaddr_in avec la famille, le port et l’adresse. Utilisez htons() pour le port et INADDR_ANY pour écouter sur toutes les interfaces.

Appelez ensuite bind() pour associer la socket à cette adresse. htons convertit l’ordre des octets de l’hôte en ordre des octets du réseau, ce qui est requis.

struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(8080);
bind(listen_fd, (struct sockaddr*)&addr, sizeof addr);

Écouter et passer en mode non bloquant

Appelez listen() pour rendre la socket passive et définir une file d’attente pour les connexions en attente. SOMAXCONN demande le maximum pris en charge par le système.

Passez ensuite la socket en mode non bloquant afin que accept() ne bloque jamais la boucle d’événements. Elle est maintenant prête à être enregistrée auprès d’epoll.

listen(listen_fd, SOMAXCONN);
set_nonblocking(listen_fd);

Enregistrer la socket d’écoute

Créez l’instance epoll et ajoutez la socket d’écoute avec EPOLLIN. Un événement de lecture sur cette socket signifie qu’un nouveau client attend d’être accepté.

Nous stockons le descripteur dans data.fd afin de pouvoir reconnaître la socket d’écoute dans la boucle.

int epfd = epoll_create1(0);
struct epoll_event ev = { .events = EPOLLIN, .data.fd = listen_fd };
epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &ev);

Accepter un client

Lorsque la socket d’écoute est lisible, appelez accept() en boucle jusqu’à EAGAIN. Chaque nouvelle socket cliente est configurée en mode non bloquant et enregistrée pour EPOLLIN.

À partir de là, epoll nous avertira chaque fois que ce client enverra des données que nous pourrons lui renvoyer.

int c = accept(listen_fd, NULL, NULL);
if (c != -1) {
    set_nonblocking(c);
    struct epoll_event cev = { .events = EPOLLIN, .data.fd = c };
    epoll_ctl(epfd, EPOLL_CTL_ADD, c, &cev);
}

La logique d’écho

Pour un client prêt, utilisez recv() pour lire dans un tampon. Si vous recevez des octets, renvoyez-les directement avec send().

Cette simple lecture suivie d’une écriture constitue l’écho. En production, vous devriez mettre en tampon les octets non envoyés, mais pour une démonstration, nous supposons que la petite réponse tient dans le tampon d’envoi.

char buf[4096];
ssize_t r = recv(fd, buf, sizeof buf, 0);
if (r > 0) {
    send(fd, buf, r, 0);
}

Détecter une déconnexion

Une valeur de retour 0 de recv() signifie que le client a effectué une fermeture ordonnée. Une valeur négative accompagnée de toute autre valeur que EAGAIN indique une véritable erreur.

Dans les deux cas, supprimez le descripteur d’epoll et appelez close() pour libérer les ressources et empêcher d’autres événements.

if (r == 0 || (r < 0 && errno != EAGAIN)) {
    epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
    close(fd);
}

La boucle complète

Assemblez les éléments : attendez les événements, déterminez si le descripteur correspond à la socket d’écoute ou à un client, puis agissez en conséquence.

Cette boucle compacte constitue un serveur d’écho concurrent pleinement fonctionnel. Un thread, de nombreux clients, aucun thread par connexion.

for (;;) {
    int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
    for (int i = 0; i < n; i++) {
        if (events[i].data.fd == listen_fd) accept_clients();
        else echo_or_close(events[i].data.fd);
    }
}

Tester et aller plus loin

Compilez sous Linux et connectez-vous avec nc localhost 8080 : tout ce que vous saisissez vous est renvoyé. Ouvrez plusieurs terminaux pour vérifier la simultanéité.

Pour le rendre plus robuste : mettez en tampon les envois partiels, gérez EPOLLOUT, passez à EPOLLET en vidant complètement les données et gérez EPOLLRDHUP pour les fermetures de moitié.

Vérification rapide

Vérifiez votre compréhension du fonctionnement du serveur d’écho.

Récapitulatif

Vous avez créé un serveur d’écho avec epoll : création, activation de SO_REUSEADDR, association, écoute et passage en mode non bloquant. Enregistrez le socket d’écoute, acceptez les clients dans une boucle et renvoyez les données avec recv()/send().

Traitez un retour 0 comme une déconnexion et fermez proprement la connexion. À partir de cette structure de base, vous pouvez développer un serveur réseau monothread hautes performances.

Questions Fréquemment Posées

La leçon « Un serveur d’écho simple » est-elle gratuite ?

Oui — le texte complet de « Un serveur d’écho simple » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C Academy, passe à CoddyKit PRO. Le cours C Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Un serveur d’écho simple » ?

Servez plusieurs clients simultanément. Tu pratiques C Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer C Academy ?

Aucune expérience préalable n'est requise. C Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.

Combien de temps prend la leçon « Un serveur d’écho simple » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon C Academy ?

Oui. Chaque leçon C Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. E/S bloquantes ou non bloquantes
  2. Configurer epoll
  3. La boucle d’événements
  4. Un serveur d’écho simple
← Retour à C Academy