Scène familière : les requêtes courtes volent comme des hirondelles, mais dès qu’on lance un gros téléversement ou qu’on télécharge un fichier lourd via un proxy mobile, la connexion se coupe en plein milieu. Le fichier est à 40 %, puis silence. Réessayer la requête aide parfois, parfois pas. Et le plus frustrant : les journaux ne disent rien, le serveur semble vivant, mais les données n’arrivent pas. Si vous avez déjà vécu ça, vous êtes au bon endroit.

Cet article ne traite pas des codes de réponse ni de la logique de réessai au niveau HTTP (il existe un contenu dédié sur les 429 et le backoff exponentiel auquel nous ferons référence). Ici, nous décortiquons le niveau transport : pourquoi TCP se brise, qui exactement coupe la connexion, comment fonctionnent trois timeout différents sur le chemin des paquets, ce qu’est le MTU et la fragmentation dans les réseaux cellulaires, et pourquoi un changement de station de base tue les sessions longues. Et surtout, nous allons construire un client qui survivra à tout cela.

Introduction : le téléchargement plante en plein vol, les requêtes courtes passent

Pourquoi ce sujet est-il si pertinent en 2026 ? Parce que les proxys mobiles sont devenus un outil de travail pour le scraping, l’automatisation, les tests et la gestion des marketplaces. Un réseau cellulaire est par nature plus instable qu’une connexion filaire. Il a été conçu pour un humain avec son téléphone qui ouvre une page, la lit puis la ferme. Il n’a pas été conçu pour une machine qui garde une même connexion TCP ouverte dix minutes et envoie un gigaoctet à travers.

D’où le paradoxe énoncé dans le titre de cette section. Les requêtes courtes passent parce qu’elles ont le temps de se terminer avant qu’un des timeout ne se déclenche ou qu’un handover (basculement entre stations de base) ne se produise. Les opérations longues vivent plus longtemps et augmentent donc la probabilité de rencontrer chacun de ces problèmes : un timeout d’inactivité, une rupture lors d’un changement de cellule, la perte d’un gros paquet à cause d’un MTU incorrect.

Ce que vous apprendrez en lisant jusqu’au bout :

  • Comment comprendre en cinq minutes qui a exactement coupé la connexion : votre client, le proxy, l’opérateur ou le serveur cible.
  • En quoi TCP keepalive diffère fondamentalement de HTTP keep-alive et pourquoi vous avez besoin des deux réglages.
  • Comment mesurer les trois timeout sur le chemin et trouver le plus court, celui qui décide du sort de la connexion.
  • Pourquoi le MTU est inférieur aux 1500 octets standard dans les réseaux cellulaires, et à quoi ressemble une panne de PMTUD (symptôme : blocage sur les grosses réponses).
  • Un code client prêt à l’emploi en Python et Node avec reprise par Range, découpage des téléversements et timeout appropriés.

Nous allons parler un langage technique, mais chaque terme sera expliqué simplement. C’est parti.

Les bases : comment fonctionne une connexion via un proxy mobile

Avant de parler des pannes, mettons-nous d’accord sur la vision d’ensemble. Lorsque vous faites une requête via un proxy mobile, le paquet traverse une longue chaîne. Comprendre cette chaîne, c’est déjà la moitié du diagnostic.

Le trajet d’un paquet du client au serveur

Imaginez le parcours d’un colis. Il passe par plusieurs étapes, et à chacune, il peut être retardé ou perdu :

  1. Votre client – le programme qui effectue la requête. Il a ses propres timeout et réglages de sockets.
  2. Le serveur proxy – reçoit votre connexion et ouvre la sienne vers la cible. Ce sont souvent deux connexions TCP distinctes assemblées.
  3. Le modem mobile et l’interface radio – la portion étroite et capricieuse. Ici, le paquet voyage par ondes radio jusqu’à la station de base.
  4. Le cœur du réseau de l’opérateur – NAT, passerelles, systèmes de priorisation du trafic.
  5. L’Internet public – les liaisons principales jusqu’au centre de données de la cible.
  6. Le serveur cible – le point final, qui a lui aussi ses limites sur la durée des connexions.

L’idée clé : une connexion via un proxy n’est pas un seul tuyau, mais au moins deux. Le client tient une connexion vers le proxy, le proxy tient une connexion vers la cible. Une rupture peut survenir sur n’importe lequel de ces segments, et les symptômes seront différents.

Qu’est-ce qu’une session et pourquoi est-elle fragile

Une connexion TCP est un canal virtuel. Physiquement, aucun câble ne vous relie au serveur : c’est juste un accord entre les deux parties pour échanger des octets numérotés. Tant que les deux se souviennent des numéros et de l’état, la connexion est vivante. Dès que l’une des deux a oublié cet état (NAT redémarré, timeout expiré, cellule changée), la connexion est en réalité morte, même si l’autre partie peut l’ignorer encore longtemps.

C’est ce qui crée ces redoutables connexions semi-ouvertes (half-open) : un côté croit le canal vivant et attend des données, tandis que l’autre a tout oublié depuis longtemps. Le client reste bloqué, aucune erreur n’arrive, le temps passe. Ça vous dit quelque chose ?

Trois niveaux où les problèmes surviennent

  • Le niveau radio – pertes de paquets, latences, changement de cellule. La nature même des réseaux cellulaires.
  • Le niveau réseau – timeout NAT de l’opérateur, MTU, fragmentation.
  • Le niveau applicatif – timeout du serveur HTTP du proxy et de la cible, limites sur la taille du corps de réponse.

Nous allons maintenant passer en revue chacun d’eux et apprendre à les distinguer.

Plongée en profondeur : qui peut couper la connexion et comment savoir qui

C’est la section de diagnostic la plus importante. Tant que vous ignorez le coupable, vous tirez à l’aveugle. Bonne nouvelle : chaque coupable a sa signature.

Quatre suspects

1. Votre client. Le coupable le plus fréquent et le plus sous-estimé. Les bibliothèques HTTP ont des timeout par défaut que vous n’avez peut-être pas remarqués. Par exemple, un timeout sur la durée totale de la requête, un timeout de lecture de socket, un timeout d’inactivité. Si votre client a coupé la connexion lui-même, les journaux afficheront une erreur du type read timeout ou socket timeout avec votre code dans la pile d’appels.

2. Le serveur proxy. Le proxy a ses propres limites : durée de vie maximale de la connexion, idle timeout, taille maximale de réponse. Quand le proxy coupe la connexion, vous obtenez souvent un connection reset soudain ou une fermeture sans réponse au milieu du corps de la réponse. Pourtant, le ping vers le proxy fonctionne et les requêtes courtes passent.

3. L’opérateur de télécommunications. Le plus discret. Les tables NAT des opérateurs ont une durée de vie pour chaque entrée. Si aucun trafic ne passe pendant un moment, l’opérateur supprime l’entrée NAT et les paquets suivants n’ont alors plus de destination. Symptôme : la connexion se bloque précisément pendant les pauses, pas pendant un transfert actif. L’opérateur est aussi le coupable lors d’un changement de station de base.

4. Le serveur cible. Il a ses propres réglages keep-alive et ses limites. Beaucoup de serveurs ferment la connexion après N requêtes ou après T secondes. Symptôme : le serveur envoie l’en-tête Connection : close ou termine proprement la connexion (FIN), plutôt que de la couper (RST).

Diagnostic par symptômes : le tableau des signatures

Examinons les signes caractéristiques pour que vous puissiez identifier le coupable en quelques minutes.

  • Rupture uniquement pendant les pauses, tout va bien pendant un transfert actif – c’est presque certainement le timeout NAT de l’opérateur ou l’idle timeout du proxy. On corrige avec du trafic keepalive.
  • Rupture toujours autour du même volume de données (par exemple, environ 8 ou 10 Mo) – limite sur la taille de réponse du proxy ou du serveur. On corrige en découpant avec Range.
  • Rupture toujours après à peu près le même temps (par exemple, exactement 60 ou 300 secondes) – limite stricte sur la durée de connexion. Cherchez le plus court des timeout.
  • Blocage précisément sur les grosses réponses, les petites passent – panne classique de PMTUD et problème de MTU. Nous y consacrons une section entière plus bas.
  • Ruptures aléatoires sans lien avec le volume ni le temps, plus fréquentes en mouvement – changement de station de base, handover, dégradation du signal radio.
  • RST immédiat lors d’une tentative d’envoi de données – la connexion est déjà morte d’un côté (semi-ouverte) ou le proxy a activement réinitialisé.

Outils de diagnostic de base

Pour distinguer un FIN (fermeture propre) d’un RST (réinitialisation brutale) et comprendre sur quel segment la rupture se produit, utilisez :

  • Journalisation au niveau de la socket – enregistrez l’heure exacte de la rupture, le nombre d’octets transférés et le type d’exception.
  • Analyse du trafic – un outil de capture de paquets montrera qui a envoyé le RST ou le FIN. Si le RST vient de l’adresse du proxy, le proxy est en cause. Si la connexion se tait simplement sans aucun paquet, c’est un nœud intermédiaire (l’opérateur) qui est en cause.
  • Mesures de contrôle – refaites la même opération via une connexion filaire directe. Si tout est stable en filaire mais que ça casse via le proxy mobile, le problème vient du segment mobile.

Observation de l’auteur : dans 70 % des cas que nous avons analysés, le coupable était le timeout NAT de l’opérateur ou l’idle timeout par défaut, et non le proxy ou le serveur. On accuse le proxy, alors que la solution tient en quelques lignes de configuration de socket.

Keep-alive et idle timeout : trois timeout sur le chemin, le plus court gagne

Voici un principe fondamental à graver dans votre mémoire : sur le chemin d’un paquet existent plusieurs timeout d’inactivité indépendants, et c’est le plus court qui décide du sort de la connexion. C’est comme une chaîne : elle casse au maillon le plus faible.

Où se trouvent les timeout

  1. L’idle timeout de votre client. Combien de temps votre programme est prêt à attendre des données sans rien recevoir. Par défaut, selon les bibliothèques, cela va de 30 secondes à l’infini.
  2. L’idle timeout du proxy. Combien de temps le proxy maintient une connexion inactive ouverte. Les valeurs typiques vont de 60 à 300 secondes.
  3. Le timeout NAT de l’opérateur. Combien de temps le cœur du réseau conserve une entrée de traduction d’adresse sans trafic. Pour TCP, c’est souvent 300 à 600 secondes, mais pour UDP et aux heures chargées, cela peut descendre à 30-60 secondes.
  4. Le timeout keep-alive du serveur cible. Combien de temps le serveur maintient la connexion entre les requêtes. Souvent 5 à 75 secondes.

Imaginez que le client soit prêt à attendre 120 secondes, que le proxy coupe après 90 et que l’opérateur purge le NAT au bout de 60. Qui gagne ? L’opérateur. La connexion mourra à la 60e seconde d’inactivité, et ni le client ni le proxy ne le sauront immédiatement.

Comment mesurer le timeout le plus court

La méthode est simple et fiable. On établit une connexion, on fait une seule requête, puis on se tait et on attend en chronométrant jusqu’à la rupture. On répète plusieurs fois pour exclure le hasard.

  1. Ouvrez une connexion via le proxy vers un serveur de test qui sait maintenir le keep-alive.
  2. Faites une seule requête courte et recevez la réponse.
  3. Ne fermez pas la connexion. Lancez un minuteur.
  4. Vérifiez régulièrement (une fois par seconde) si la connexion est toujours vivante en essayant de lire depuis la socket en mode non bloquant.
  5. Notez le moment où un RST, un FIN arrive ou où la socket devient illisible.

Faites la mesure trois fois. Si la rupture se produit systématiquement autour de 60 secondes, c’est votre plafond d’inactivité. Il faut donc envoyer du trafic keepalive plus souvent qu’une fois toutes les 60 secondes, avec une bonne marge – par exemple toutes les 20 à 25 secondes.

La stratégie pour vaincre l’idle timeout

Puisque le timeout le plus court décide de tout, notre objectif est de ne pas laisser la connexion inactive plus longtemps que cette limite. Deux approches :

  • Remplir la connexion avec du trafic utile – lors d’un transfert actif, les idle timeout ne se déclenchent pas, car il n’y a pas d’inactivité. C’est pourquoi un téléchargement continu souffre rarement d’un idle timeout, mais plutôt de limites de taille et de durée de vie.
  • Envoyer des sondes keepalive pendant les pauses – quand il n’y a pas de données utiles (par exemple, vous attendez la génération d’un rapport sur le serveur), il faut maintenir la connexion avec du trafic artificiel. C’est là qu’interviennent les deux mécanismes keep-alive que nous allons détailler.

TCP keepalive vs HTTP keep-alive : des mécanismes différents, les deux sont nécessaires

Une énorme confusion règne dans le secteur à cause de noms similaires. TCP keepalive et HTTP keep-alive sont des choses complètement différentes, qui opèrent à des niveaux différents. Et pour un client mobile robuste, les deux sont nécessaires.

HTTP keep-alive : la réutilisation de la connexion

HTTP keep-alive (aussi appelé connexion persistante) consiste à ne pas ouvrir une nouvelle connexion TCP à chaque requête. À la place, une même connexion sert plusieurs requêtes successives. C’est le niveau applicatif.

Pourquoi est-ce important pour les réseaux mobiles ? Établir une nouvelle connexion TCP via un réseau cellulaire coûte cher. La triple poignée de main, plus une poignée de main TLS si le chiffrement est utilisé. Sur un canal radio à forte latence, cela peut prendre des centaines de millisecondes. En réutilisant la connexion, vous économisez ce temps à chaque requête suivante.

Mais ! HTTP keep-alive n’aide en rien contre le timeout NAT de l’opérateur pendant les pauses. Il permet simplement de garder la connexion ouverte pour la requête suivante, mais il ne génère pas de trafic entre-temps.

TCP keepalive : le pouls au niveau transport

TCP keepalive est un mécanisme du protocole TCP lui-même. Le système d’exploitation envoie périodiquement un paquet de service vide (sonde keepalive) pour vérifier si l’autre partie est vivante, et au passage rafraîchir les entrées dans les tables NAT intermédiaires. C’est le niveau du noyau de l’OS.

C’est précisément TCP keepalive qui est votre arme principale contre les timeout NAT des opérateurs et les idle timeout des nœuds intermédiaires. Chaque sonde est du trafic qui remet à zéro le compteur d’inactivité sur tout le chemin.

TCP keepalive a trois paramètres clés :

  • keepalive idle (ou keepalive time) – après combien de secondes d’inactivité commencer à envoyer des sondes. Par défaut, dans la plupart des OS, c’est 7200 secondes, soit deux heures. Une catastrophe pour les réseaux mobiles.
  • keepalive interval – l’intervalle entre les sondes si aucune réponse n’arrive.
  • keepalive count (probes) – combien de sondes sans réponse consécutives considérer comme signe de connexion morte.

Valeurs recommandées pour les réseaux mobiles

Les deux heures par défaut sont totalement inadaptées. L’opérateur purgera le NAT bien avant la première sonde. Voici des valeurs qui fonctionnent, éprouvées par la pratique :

  • keepalive idle : 15-25 secondes. On commence à envoyer des sondes après une courte pause pour devancer à coup sûr le timeout NAT le plus agressif.
  • keepalive interval : 10-15 secondes. Si la sonde n’arrive pas, on répète après un court intervalle.
  • keepalive count : 3-4. Après trois ou quatre sondes sans réponse, on considère la connexion comme morte et on la rétablit, sans attendre un blocage infini.

Cette combinaison offre un double avantage : la connexion n’est pas coupée par l’opérateur pendant les pauses, et si elle meurt quand même (par exemple à cause d’un handover), le client le découvre en 45 à 70 secondes au lieu d’heures. Détecter rapidement une connexion morte, c’est déjà la moitié de la robustesse.

Pourquoi les deux réglages sont nécessaires

Une analogie. HTTP keep-alive, c’est comme réserver une salle de réunion pour toute la journée afin de ne pas avoir à la réserver à chaque fois. TCP keepalive, c’est passer régulièrement dans cette salle pour que l’agent d’entretien ne pense pas qu’elle est vide et ne la verrouille pas. Vous avez réservé mais vous n’entrez pas – on la verrouille. Vous entrez mais vous réservez à chaque fois – vous perdez du temps. Il faut les deux.

MTU et fragmentation : pourquoi les paquets sont plus petits dans les réseaux cellulaires

Passons à la cause de blocage la plus sous-estimée. Si vos petites réponses passent mais que les grosses se figent complètement, il y a 90 % de chances que ce soit une histoire de MTU et de PMTUD cassé.

Qu’est-ce que le MTU en termes simples

MTU (Maximum Transmission Unit) – c’est la taille maximale d’un paquet pouvant être envoyé sur le réseau sans être découpé. Dans l’Ethernet classique, c’est 1500 octets. Imaginez que c’est la largeur d’une porte : un meuble plus large que la porte devra être démonté pour passer.

Le problème, c’est que dans les réseaux cellulaires, le MTU effectif est souvent inférieur à 1500. La raison, c’est l’encapsulation. Le trafic mobile est enveloppé dans des couches protocolaires supplémentaires au sein du réseau de l’opérateur. Chaque couche ajoute ses octets d’en-tête, et il reste moins de place pour les données utiles. Le MTU réellement utilisable dans les réseaux mobiles se situe souvent entre 1400 et 1480 octets, parfois même moins.

Qu’est-ce que le PMTUD et pourquoi se casse-t-il

PMTUD (Path MTU Discovery) – c’est le mécanisme qui détermine automatiquement la taille maximale de paquet sur tout le chemin. Il fonctionne ainsi : le client envoie un gros paquet avec le drapeau Don't Fragment (ne pas fragmenter). Si sur le trajet il rencontre un nœud avec un MTU plus petit, ce nœud jette le paquet et renvoie un message ICMP spécial de type fragmentation needed indiquant la taille autorisée. Le client reçoit l’indication et réduit la taille de ses paquets.

Un beau schéma. Mais il repose sur une condition fragile : les messages ICMP doivent revenir jusqu’au client. Or, en réalité, beaucoup de réseaux, de pare-feu et de configurations de sécurité bloquent complètement ICMP. Et c’est là que se produit la catastrophe appelée PMTUD black hole (trou noir).

À quoi ressemble une panne de PMTUD : anatomie d’un blocage

Le scénario est classique et très caractéristique :

  1. Le client établit la connexion. La poignée de main passe en petits paquets – tout va bien.
  2. Le client envoie une courte requête – le petit paquet passe, la réponse arrive. Les petites réponses fonctionnent.
  3. Le serveur commence à envoyer une grosse réponse avec des paquets pleine taille de 1500 octets et le drapeau Don't Fragment.
  4. Quelque part sur le chemin, un nœud avec un MTU de 1400 jette ces paquets, car ils sont trop grands et ne peuvent pas être fragmentés.
  5. Le nœud renvoie un ICMP fragmentation needed, mais cet ICMP est bloqué par le pare-feu et n’arrive jamais.
  6. Le serveur ne reçoit pas l’indication, continue d’envoyer les mêmes gros paquets, ils sont à nouveau jetés. Boucle infinie.
  7. Résultat : les petits paquets (en-têtes, ACK) passent, mais les données de réponse non. La connexion se fige complètement au milieu d’une grosse réponse.

Voilà pourquoi les requêtes courtes passent alors que les grosses réponses se bloquent. Ce n’est pas de la magie, c’est le trou noir PMTUD. Et c’est sans doute la source la plus fréquente de cheveux blancs chez les ingénieurs qui travaillent avec du trafic mobile.

Comment traiter le problème de MTU

Il existe plusieurs niveaux de solution, du niveau applicatif au niveau réseau :

  • MSS clamping. La méthode la plus fiable au niveau réseau. MSS (Maximum Segment Size) est la taille maximale d’un segment TCP que les deux parties conviennent au tout début, lors de la poignée de main. Si on limite explicitement le MSS pour que le paquet final tienne dans le MTU réel (par exemple, MSS 1360-1400), le serveur enverra dès le départ des paquets de la bonne taille, et aucun ICMP ne sera nécessaire. Cela soigne le trou noir à la racine.
  • Réduction du MTU de l’interface. Si vous contrôlez le modem ou la machine par laquelle passe le trafic, vous pouvez régler le MTU de l’interface à 1400 ou moins. Tous les paquets sortants seront alors garantis de ne pas dépasser une taille sûre.
  • Autoriser la traversée d’ICMP. Si vous avez le contrôle sur les pare-feu sur le chemin, autorisez les messages ICMP de type fragmentation needed. Le PMTUD standard fonctionnera alors comme prévu.
  • Niveau applicatif. Si vous téléchargez un gros fichier, découpez-le en parties via des requêtes Range. Chaque partie est un transfert court distinct qui a moins de chances de se heurter aux problèmes des gros flux. Nous y reviendrons en détail dans la partie pratique.

Le point clé : même si vous ne contrôlez pas le réseau, vous pouvez presque toujours influencer le MSS via les réglages de connexion ou via les paramètres du service proxy. Un bon fournisseur de proxys mobiles configure déjà un MSS clamping correct de son côté, vous évitant les trous noirs. C’est l’un des critères de qualité d’un service.

Changement de station de base et bascule entre réseaux : pourquoi TCP n’y survit pas

Parlons maintenant de l’incompatibilité la plus fondamentale. Le réseau cellulaire est conçu pour la mobilité, pas TCP. C’est un conflit au niveau de l’architecture.

Pourquoi TCP est lié à l’adresse

Une connexion TCP est définie de manière unique par un quadruplet : adresse source, port source, adresse de destination, port de destination. C’est comme l’adresse postale de la connexion. Si un seul élément change, c’est une autre connexion, et l’ancienne devient invalide.

Et que se passe-t-il dans un réseau mobile ? Dans certains scénarios de changement de station de base ou de bascule entre technologies (par exemple entre différentes générations de réseau ou entre réseaux), l’adresse IP externe du nœud mobile peut changer. Et là, TCP est impuissant : il ne sait pas poursuivre une connexion avec une nouvelle adresse. L’ancienne connexion est simplement morte. Toutes les données qui étaient en transit sont perdues.

Handover : pas toujours fatal, mais toujours risqué

Pour être juste, les réseaux modernes s’efforcent de rendre le handover transparent : conserver la même IP lors d’un changement de cellule. Souvent, cela réussit et vous ne remarquez rien. Mais parfois, il y a un changement d’IP, une brève coupure radio d’une seconde ou deux, ou un pic de pertes de paquets. Pour une requête courte, c’est imperceptible. Pour une session de dix minutes, c’est une loterie à chaque fois.

Symptômes d’une rupture lors d’un handover

  • Les ruptures sont aléatoires, sans lien avec le volume de données ni le temps.
  • La fréquence des ruptures augmente si l’appareil se déplace physiquement (ce qui est typique des proxys mobiles sur de vraies cartes SIM).
  • Après une rupture, une nouvelle connexion s’établit normalement – le réseau est vivant, seule l’ancienne connexion est morte.

Que faire : accepter et construire de la robustesse

Impossible de vaincre le changement d’IP au niveau TCP. Mais on peut construire un client pour qui la rupture de connexion est une situation normale, et non une urgence. La philosophie est simple : une connexion via un réseau mobile est éphémère par définition, et le client doit savoir la rétablir sans couture et reprendre le travail là où il s’est arrêté.

Voici les techniques concrètes que nous allons implémenter dans le code :

  • Idempotence des opérations. Concevez vos requêtes pour pouvoir les répéter sans risque. Un téléchargement par Range est idempotent : une nouvelle requête du même intervalle d’octets donne le même résultat.
  • Reprendre, pas recommencer. En cas de rupture, ne recommencez pas le fichier depuis le début, reprenez à partir du dernier octet reçu. Cela économise du trafic et du temps.
  • Détection rapide de la mort de la connexion. Grâce à un TCP keepalive agressif, comme nous l’avons vu, vous saurez qu’une connexion est morte en quelques secondes, pas en quelques minutes.
  • Transactions courtes. Plus un transfert est court, moins il a de chances d’être surpris par un handover. Découper un gros téléversement en parties découle directement de ce principe.

Pratique avec Python : un client robuste avec reprise et timeout

Assez de théorie, passons à la pratique. Commençons par Python. Nous allons construire un client qui : configure TCP keepalive, définit des timeout raisonnables, télécharge un fichier par morceaux via Range et sait reprendre après une rupture.

Étape 1 : configurer TCP keepalive sur la socket

Les bibliothèques HTTP standard ne configurent pas un keepalive agressif par défaut. Il faut accéder à la socket. Dans l’écosystème requests, cela se fait via un adaptateur de transport personnalisé qui définit les options de la socket : active keepalive, idle à 20 secondes, interval à 10 secondes, count à 3. Au niveau de la description, la logique est la suivante : nous enregistrons un adaptateur qui, à la création de la connexion, applique les paramètres nécessaires au niveau bas.

La partie significative de la configuration, en pseudo-code : activer l’option SO_KEEPALIVE, puis définir TCP_KEEPIDLE à 20, TCP_KEEPINTVL à 10, TCP_KEEPCNT à 3. Les noms des options varient légèrement selon les systèmes d’exploitation, donc en production on les sélectionne en vérifiant la plateforme.

Étape 2 : des timeout raisonnables

Règle clé : définissez toujours les timeout explicitement et séparez le timeout de connexion du timeout de lecture. L’absence de timeout est un piège où le client reste bloqué indéfiniment sur une connexion semi-ouverte.

  • Connect timeout : 10 secondes. L’établissement d’une connexion via un réseau mobile est plus lent, mais 10 secondes suffisent avec une marge.
  • Read timeout : 30 secondes. C’est le timeout d’inactivité entre les morceaux de données, pas pour tout le transfert. Si aucun octet n’arrive en 30 secondes, la connexion est considérée comme problématique.
  • Le budget global de l’opération est contrôlé séparément au niveau de la logique de reprise, et non par un timeout géant sur toute la requête.

Étape 3 : téléchargement par Range avec reprise

Voici l’idée de l’algorithme. On ouvre le fichier cible en écriture. On vérifie la taille déjà téléchargée (si le fichier existe partiellement). On demande l’intervalle restant via l’en-tête Range : bytes depuis la position actuelle jusqu’à la fin. On écrit le flux dans le fichier au fur et à mesure. Si on attrape une rupture (exception de lecture, coupure de connexion), pas de panique : on regarde combien d’octets sont déjà sur le disque, et on répète la requête avec une nouvelle position de départ. On continue jusqu’à ce que le fichier soit entièrement reçu.

Logique pas à pas, en mots :

  1. Déterminer la taille totale du fichier via une requête d’en-têtes (HEAD ou GET avec Range : bytes=0-0 pour lire Content-Range).
  2. Vérifier la taille locale de la partie déjà téléchargée.
  3. Si la taille locale est égale à la taille totale, le fichier est prêt, on sort.
  4. Sinon, créer une requête avec Range à partir de la taille locale.
  5. Lire la réponse par morceaux de 64 à 256 kilo-octets, en les ajoutant au fichier.
  6. En cas de succès, vérifier l’intégrité (taille, et éventuellement somme de contrôle).
  7. En cas de rupture, incrémenter le compteur de tentatives, appliquer une courte pause et revenir à l’étape 2.
  8. Limiter le nombre maximal de tentatives au niveau transport (par exemple 5 à 8), pour ne pas boucler indéfiniment en cas de problème système.

Point important : assurez-vous que le serveur prend en charge Range. Le signe est l’en-tête Accept-Ranges : bytes dans la réponse et le code 206 Partial Content sur une requête Range. Si le serveur renvoie 200 et ignore Range, la reprise est impossible et il faudra tout télécharger, mais dans ce cas, le keepalive et un MSS correct sont d’autant plus importants.

Étape 4 : découper un gros téléversement

Quand vous ne téléchargez pas mais que vous envoyez un gros volume (par exemple, transmettre des données ou recevoir un gros rapport), appliquez le même principe de découpage. Divisez la tâche en pages ou en morceaux de taille fixe. Chaque morceau est une courte transaction distincte avec sa propre gestion d’erreurs. Tenez un journal de progression : quels morceaux sont déjà confirmés. En cas de rupture, ne rejouez que les morceaux non confirmés. Cela transforme une opération fragile de dix minutes en une série de courtes opérations robustes.

Concernant les stratégies de réessai basées sur les codes de réponse du serveur, nous ne les abordons pas ici, car c’est le sujet d’un article dédié sur les 429 et le backoff exponentiel, à consulter après celui-ci. Notre focus est le transport : rupture, timeout, taille.

Pratique avec Node.js : un agent HTTP robuste et le streaming

Appliquons maintenant les mêmes principes dans l’écosystème Node.js. Ici, l’objet central est l’agent, qui gère le pool de connexions.

Étape 1 : configurer l’agent avec keep-alive

Dans Node, on crée un agent HTTP ou HTTPS avec keepAlive activé. Le paramètre keepAlive true force l’agent à réutiliser les connexions (c’est le niveau HTTP). En plus, on configure keepAliveMsecs, l’intervalle d’envoi des sondes TCP keepalive au niveau de la socket. Pour les réseaux mobiles, réglez keepAliveMsecs autour de 15000-20000 millisecondes pour devancer le timeout NAT de l’opérateur. Limitez aussi maxSockets et maxFreeSockets pour ne pas créer trop de connexions inutiles.

Étape 2 : les timeout à différents niveaux

Dans Node, les timeout se configurent à plusieurs endroits, et il est important de n’en oublier aucun :

  • Le timeout de connexion – via une option sur la requête ou via un gestionnaire d’événement de connexion de la socket.
  • Le timeout d’inactivité de la socket – la méthode qui définit le socket timeout. À son déclenchement, il faut explicitement détruire la socket et traiter cela comme une rupture. Node ne ferme pas automatiquement la socket en cas de timeout, il émet seulement un événement – on l’oublie souvent, et la connexion continue de rester bloquée.
  • La gestion des événements error et close sur la requête et sur la socket – chacun doit déclencher une logique de nouvelle tentative contrôlée.

Les valeurs recommandées sont similaires à Python : connect environ 10 secondes, idle de socket environ 30 secondes, sondes keepalive toutes les 15 à 20 secondes.

Étape 3 : streaming du téléchargement avec reprise

Dans Node, il est naturel de travailler avec des flux. La logique de reprise est la même qu’en Python : on vérifie la taille du fichier local, on ouvre un flux d’écriture en mode ajout, on crée une requête avec l’en-tête Range à partir de la taille actuelle, on abonne des gestionnaires aux événements data, end et error. À l’événement data, on écrit le morceau dans le fichier. À l’événement end, on vérifie si le fichier est entièrement reçu. À l’événement error ou à une fermeture prématurée, quand on a reçu moins que prévu, on lance une reprise depuis la nouvelle position.

Le point crucial de la robustesse dans Node est la gestion correcte de la fin prématurée du flux. L’événement end peut se produire même si tout n’a pas été reçu, en cas de coupure de connexion. Il faut donc toujours comparer le volume réellement reçu avec celui attendu d’après l’en-tête Content-Length ou Content-Range. Ne vous fiez pas uniquement au déclenchement de end.

Étape 4 : envelopper les nouvelles tentatives au niveau transport

Enveloppez toute l’opération de téléchargement dans une boucle avec un nombre limité de tentatives. Entre les tentatives, une courte pause (pour les ruptures transport, 1 à 3 secondes suffisent, car la cause n’est pas une surcharge du serveur mais un événement réseau). Comptez les tentatives. Épuisez la limite, remontez l’erreur avec des informations de diagnostic : combien d’octets ont été reçus, quel type d’erreur, combien de tentatives ont été effectuées. Ce diagnostic est précieux lors de l’analyse des incidents.

Erreurs courantes : ce qu’il ne faut pas faire

Passons en revue les anti-patterns que nous rencontrons régulièrement dans le code des autres. Évitez-les, et la moitié des problèmes disparaîtra.

Erreur 1 : l’absence de timeout explicites

La plus courante et la plus douloureuse. Un client sans timeout sur une connexion semi-ouverte reste bloqué pour toujours. Le thread est bloqué, la ressource n’est pas libérée, et vous pensez que l’opération est toujours en cours. Définissez toujours les timeout explicitement. L’absence de timeout, ce n’est pas une patience infinie, c’est une bombe cachée.

Erreur 2 : se fier au TCP keepalive par défaut

Les deux heures par défaut rendent TCP keepalive inutile pour les réseaux mobiles. Beaucoup activent SO_KEEPALIVE et s’en contentent, sans se douter que la première sonde partira seulement après 7200 secondes, alors que l’opérateur a déjà tout purgé depuis longtemps. Configurez idle, interval et count explicitement.

Erreur 3 : retélécharger entièrement le fichier à chaque rupture

Une rupture à 95 % et un redémarrage complet depuis zéro, c’est non seulement du temps perdu, mais aussi du trafic mobile gaspillé, qui est généralement facturé sur un proxy. La reprise par Range est indispensable pour tout téléchargement volumineux.

Erreur 4 : ignorer le MTU et le MSS

Les gens luttent pendant des mois contre les blocages des grosses réponses, en changeant les timeout et les proxys, alors que la cause est le trou noir PMTUD. Si les grosses réponses se bloquent et que les petites passent, vérifiez d’abord le MTU et configurez le MSS clamping. Cela vous fera gagner des semaines.

Erreur 5 : confondre les ruptures transport avec les réponses du serveur

Une rupture transport (RST, timeout de lecture, socket morte) et une réponse du serveur avec un code d’erreur sont des situations différentes avec des stratégies de réaction différentes. Pour les ruptures transport, des répétitions rapides avec une courte pause et une reprise sont adaptées. Pour les réponses du serveur avec des codes comme 429, il faut un backoff exponentiel – et c’est le sujet d’un article séparé. Ne mélangez pas ces deux couches dans un même gestionnaire.

Erreur 6 : des répétitions trop agressives

Une boucle infinie de répétitions sans limite, en cas de problème système (par exemple, proxy totalement indisponible), devient une charge parasite. Fixez toujours un plafond au nombre de tentatives et terminez l’opération intelligemment avec un diagnostic.

Erreur 7 : ne pas vérifier l’intégrité du résultat

Le fait que le téléchargement soit terminé ne signifie pas que les données reçues sont correctes. Une rupture peut laisser un fichier tronqué qui semble complet selon tous les critères formels. Vérifiez toujours la taille, et pour les données importantes, la somme de contrôle.

Erreur 8 : garder une même connexion trop longtemps

Plus une connexion via un réseau mobile vit longtemps, plus la probabilité cumulée de rencontrer un handover, un changement d’IP ou un timeout NAT est élevée. Réinitialiser périodiquement la connexion n’est pas une faiblesse, mais une hygiène raisonnable. N’ayez pas peur de recréer les connexions.

Outils et ressources pour diagnostiquer et construire de la robustesse

Le bon outil fait gagner des heures. Voici l’arsenal à garder à portée de main.

Diagnostic réseau et paquets

  • Capture et analyse du trafic. L’outil de capture de paquets est votre microscope. Il montrera qui a envoyé le RST, si le ICMP fragmentation needed est bien arrivé, quelle taille ont réellement les paquets, où le flux se coupe. Sans lui, le diagnostic du MTU et l’identification du coupable deviennent de la divination.
  • Utilitaires de vérification du chemin. Les outils de traceroute et de vérification du MTU aident à comprendre où la taille des paquets chute sur le chemin. Certains modes recherchent spécifiquement la taille maximale de paquet qui passe – exactement ce qu’il faut pour configurer le MSS.
  • Serveurs d’écho de test. Un simple serveur capable de maintenir le keep-alive et de renvoyer des données d’une taille donnée est indispensable pour mesurer les idle timeout et reproduire les problèmes de grosses réponses dans des conditions contrôlées.

Bibliothèques et approches pour le client

  • Clients HTTP avec réglage flexible des sockets. Choisissez des bibliothèques qui donnent accès aux paramètres de connexion et permettent de définir les timeout et le keepalive à bas niveau.
  • Mécanismes de streaming. Le traitement en flux du corps de réponse est indispensable pour les gros téléchargements – vous ne devez pas garder toute la réponse en mémoire.
  • Journalisation de la progression. Un simple stockage d’état (quels morceaux ont été reçus, combien d’octets sur le disque) rend la reprise triviale.

La qualité de l’infrastructure proxy

Soulignons-le : une grande partie des problèmes de transport se règle du côté d’un fournisseur de proxy de qualité. Un MSS clamping correctement configuré, des idle timeout adaptés, une conservation stable de l’IP lors d’un handover, une gestion transparente du keep-alive – ce sont les signes d’un service mature. Des services comme MobileProxy.space conçoivent leur infrastructure en tenant compte de ces subtilités de transport, ce qui évite une partie des maux de tête au client. Mais même avec un proxy idéal, le client doit être robuste – car le canal radio est imprévisible par nature.

Études de cas et résultats : comment cela fonctionne en pratique

Examinons quelques cas généralisés qui reflètent des situations typiques et leurs solutions. Les chiffres sont moyennés, mais reflètent des ordres de grandeur réels.

Cas 1 : un téléversement de catalogue se bloquait au milieu

Situation. Une équipe téléversait un gros catalogue de produits via un proxy mobile en une seule requête. Réponse d’environ 15 méga-octets. Le blocage survenait régulièrement vers 6-8 méga-octets, sans erreur, juste le silence, jusqu’à ce que le timeout global se déclenche après quelques minutes.

Diagnostic. Les petites requêtes passaient parfaitement. La capture de trafic a montré que les gros paquets partaient avec le drapeau Don't Fragment, et que le ICMP fragmentation needed ne revenait pas. Un trou noir PMTUD classique.

Solution. Nous avons configuré le MSS clamping sur une valeur garantissant un paquet dans la limite du MTU réel du réseau mobile, et nous avons découpé le téléversement en requêtes paginées de 2 méga-octets.

Résultat. Les blocages ont complètement disparu. Le temps de téléversement est devenu prévisible, et en cas de rares ruptures, seule une page était rejouée, pas tout le catalogue. Le taux de réussite est passé d’environ 40 % à quasiment 100 %.

Cas 2 : la connexion mourait pendant les temps d’attente

Situation. Le client envoyait une demande de génération d’un rapport lourd, le serveur réfléchissait pendant 90 à 120 secondes, puis devait renvoyer le résultat. Mais au moment où le rapport était prêt, la connexion était déjà morte.

Diagnostic. La mesure de l’idle timeout a montré une rupture stable autour de 60 secondes d’inactivité. Le coupable : le timeout NAT de l’opérateur – pendant l’attente, aucun trafic ne passait.

Solution. Nous avons activé TCP keepalive avec idle à 20 secondes et interval à 10. Désormais, pendant l’attente, la connexion était rafraîchie par des sondes de service toutes les 20 secondes.

Résultat. La connexion survivait jusqu’à ce que le rapport soit prêt. Les ruptures pendant les pauses ont cessé. Bonus supplémentaire : le client détectait les connexions réellement mortes en 45 à 60 secondes au lieu de rester bloqué pendant des minutes.

Cas 3 : ruptures aléatoires lors d’un scraping actif

Situation. Des sessions de scraping de longue durée se coupaient de manière chaotique, sans lien avec le volume ni le temps. Particulièrement souvent à certaines heures.

Diagnostic. Les signes indiquaient un changement d’IP lors du handover. Après la rupture, une nouvelle connexion s’établissait instantanément – le réseau était vivant.

Solution. Nous avons repensé le client selon la philosophie des connexions éphémères : transactions courtes idempotentes, journal de progression, réétablissement rapide de la connexion en cas de rupture, répétitions limitées avec une courte pause.

Résultat. Les ruptures n’ont pas disparu physiquement (on ne peut pas vaincre le changement d’IP), mais elles ont cessé d’être un problème. Chaque rupture coûtait la répétition d’une courte transaction – une fraction de seconde. La fiabilité globale du processus a augmenté de façon spectaculaire, et les ingénieurs ont arrêté de monter la garde devant les journaux la nuit.

Conclusion générale sur les cas

Remarquez la régularité : dans chaque cas, la solution ne venait pas du remplacement du proxy, mais de la compréhension du niveau transport et d’un réglage correct du client. Le diagnostic par symptômes a identifié le coupable précis, puis le traitement a été ciblé et rapide.

FAQ : questions fréquentes sur les coupures de connexion dans les réseaux mobiles

Pourquoi les requêtes courtes fonctionnent via un proxy mobile alors que les longues se coupent ?

Parce que les opérations longues vivent plus longtemps et ont le temps de rencontrer chacun des problèmes de transport : idle timeout pendant les pauses, limite de taille de réponse, limite de durée de vie de la connexion, handover avec changement d’IP et trou noir PMTUD sur les gros paquets. Les requêtes courtes se terminent avant que l’un de ces éléments ne se déclenche. La solution est de configurer le keepalive, le MSS et d’implémenter la reprise par Range.

Comment savoir qui coupe réellement la connexion : le proxy, l’opérateur ou le serveur ?

Regardez la signature. Les ruptures pendant les pauses : timeout NAT de l’opérateur ou idle du proxy. Rupture à volume fixe : limite de taille du proxy ou du serveur. Rupture à temps fixe : limite de durée de vie. Blocage sur les grosses réponses : MTU et PMTUD. Ruptures aléatoires en mouvement : handover. Pour une réponse précise, utilisez la capture de trafic : elle montrera de quelle adresse vient le RST et si le ICMP est arrivé.

Quelle est la différence entre TCP keepalive et HTTP keep-alive ?

HTTP keep-alive fonctionne au niveau applicatif et permet de réutiliser une même connexion pour plusieurs requêtes, économisant sur l’établissement. TCP keepalive fonctionne au niveau du noyau de l’OS et envoie périodiquement des sondes de service, maintenant la connexion vivante pendant les pauses et rafraîchissant le NAT. Le premier économise du temps sur les nouvelles requêtes, le second évite la rupture en inactivité. Les deux sont nécessaires.

Quelles valeurs de TCP keepalive définir pour les réseaux mobiles ?

Point de départ : idle 15-25 secondes, interval 10-15 secondes, count 3-4. Cette combinaison devance les timeout NAT agressifs des opérateurs et assure en même temps une détection rapide des connexions mortes. Ajustez les valeurs précises en mesurant votre idle timeout chez votre opérateur et proxy.

Qu’est-ce que le trou noir PMTUD et comment le reconnaître ?

C’est une situation où un nœud sur le chemin jette les paquets trop grands, tandis que son notification ICMP indiquant de réduire la taille est bloquée et n’arrive jamais à l’expéditeur. Résultat : les gros paquets sont perdus indéfiniment, alors que les petits passent. On le reconnaît au symptôme : la poignée de main et les petites réponses fonctionnent, mais les grosses réponses se figent complètement. Cela se soigne avec le MSS clamping ou en réduisant le MTU.

Peut-on conserver une connexion TCP lors d’un changement de station de base ?

Si le réseau conserve la même IP externe lors du handover, oui, la connexion survivra au basculement, peut-être avec un court délai. Si l’IP change, non, l’ancienne connexion TCP est irrémédiablement morte, car TCP est strictement lié au couple d’adresses et de ports. La bonne stratégie n’est pas de tenter de conserver la connexion à tout prix, mais de construire un client qui rétablit la connexion sans couture et reprend là où elle s’est coupée.

Comment bien reprendre un téléchargement après une rupture ?

Vérifiez si le serveur prend en charge Range (l’en-tête Accept-Ranges : bytes et le code 206 sur une requête Range). En cas de rupture, déterminez la taille de la partie déjà reçue et demandez le reste via l’en-tête Range à partir de cet octet, en continuant d’écrire dans le même fichier. Répétez jusqu’à réception complète, en limitant le nombre de tentatives. À la fin, comparez toujours la taille finale avec celle attendue.

Quels timeout définir dans un client HTTP pour un proxy mobile ?

Séparez le timeout d’établissement de la connexion (environ 10 secondes) et le timeout d’inactivité de lecture (environ 30 secondes, comme pause entre les morceaux de données, pas pour tout le transfert). Contrôlez le budget global de l’opération au niveau de la logique de reprise, plutôt qu’avec un énorme timeout. Ne laissez jamais les timeout illimités.

Faut-il changer quelque chose si les stratégies de répétition basées sur les codes de réponse sont déjà configurées ?

Oui. Les répétitions basées sur les codes de réponse (par exemple, la gestion du 429 avec backoff exponentiel) relèvent du niveau applicatif, un sujet distinct. Les ruptures transport – RST, timeout de lecture, sockets mortes – exigent leur propre logique : répétitions rapides avec une courte pause, reprise, keepalive et MSS correct. Ces deux couches ne se remplacent pas et doivent coexister dans le client.

Le choix du fournisseur de proxy influence-t-il la robustesse du transport ?

Considérablement. Un fournisseur mature configure le MSS clamping, des idle timeout adaptés, essaie de conserver l’IP lors du handover et gère correctement le keep-alive. Cela élimine une partie des problèmes avant même votre code. Mais même un proxy idéal ne dispense pas de construire un client robuste, car le canal radio est imprévisible par nature.

Conclusion : la connexion est éphémère, mais les données doivent arriver

Nous avons parcouru le chemin du symptôme au client robuste. Résumons l’essentiel pour que cet article devienne votre référence.

Premièrement. La rupture d’une connexion longue via un proxy mobile n’est pas un mystère, mais la conséquence de mécanismes bien concrets : idle timeout à trois niveaux, limites de taille et de durée, problèmes de MTU et handover. Chacun a sa signature, et le diagnostic par symptômes mène presque toujours au coupable.

Deuxièmement. Le timeout le plus court sur le chemin décide du sort de la connexion. Mesurez-le et configurez TCP keepalive de manière plus agressive que cette limite – idle 15-25 secondes pour les réseaux mobiles. N’oubliez pas que TCP keepalive et HTTP keep-alive sont des mécanismes différents, et que les deux sont nécessaires.

Troisièmement. Si les grosses réponses se bloquent alors que les petites passent, c’est presque certainement un trou noir PMTUD. Cela se soigne avec le MSS clamping et un MTU correct. Ne perdez pas des semaines à multiplier les timeout, vérifiez la taille des paquets en premier.

Quatrièmement. On ne peut pas vaincre le changement d’IP lors d’un handover, mais on peut le rendre sans danger. Construisez le client autour de l’éphémérité de la connexion : transactions courtes idempotentes, reprise par Range, journal de progression, réétablissement rapide, répétitions limitées et vérification obligatoire de l’intégrité.

Vos prochaines étapes sont simples. Mesurez l’idle timeout sur votre proxy et votre opérateur. Activez et configurez TCP keepalive. Vérifiez le comportement sur les grosses réponses et, si nécessaire, configurez le MSS. Implémentez la reprise par Range. Et étudiez aussi le contenu connexe sur les stratégies de répétition au niveau des codes de réponse – 429 et backoff exponentiel – pour couvrir également la couche applicative, pas seulement le transport.

Un réseau mobile est imprévisible par nature. Mais un client construit dans le respect de cette nature transforme cette imprévisibilité, passant d’une source de gardes de nuit à un simple bruit de fond routinier. La connexion est éphémère – et c’est normal. L’essentiel est que les données arrivent quand même. Vous savez maintenant comment y parvenir.