← Retour au Transfert de fichier

Comment ça marche

Une explication technique du processus de transfert pair-à-pair

📋 Vue d’ensemble

File Transfer utilise WebRTC (Web Real-Time Communication) pour établir un canal de données direct et chiffré entre deux navigateurs. Une fois connecté, le fichier est découpé en petits blocs binaires et diffusé depuis le navigateur de l’expéditeur vers celui du destinataire en temps réel — sans passer par aucun serveur intermédiaire.

Le processus comporte cinq phases distinctes :

  1. Signalisation — échange des paramètres de connexion via un serveur relais
  2. Négociation ICE — recherche du meilleur chemin réseau entre les deux pairs
  3. Ouverture du canal de données — établissement du RTCDataChannel chiffré
  4. Diffusion en blocs — transfert du fichier en blocs binaires de 64 Ko
  5. Reconnexion et reprise — récupération après une coupure en cours de transfert

🔑 Étape 1 — La clé UUID et la signalisation

Lorsque l’expéditeur sélectionne un fichier, l’application génère un UUID v4 aléatoire (Universally Unique Identifier), par exemple :

550e8400-e29b-41d4-a716-446655440000

Cet UUID devient l’identifiant pair de l’expéditeur dans le réseau PeerJS. Le navigateur de l’expéditeur enregistre cet identifiant auprès d’un serveur de signalisation public opéré par PeerJS. Le lien partagé par l’expéditeur est simplement l’adresse de la page suivie de ?receive= et de cet UUID.

Le seul rôle du serveur de signalisation est d’aider les deux navigateurs à se trouver et à échanger les métadonnées de connexion WebRTC (appelées offres et réponses SDP). Il ne voit jamais les données des fichiers.

Que reçoit le serveur de signalisation ?

Le serveur de signalisation échange uniquement deux types de messages :

Une fois que les deux navigateurs ont échangé ces informations, le serveur de signalisation n’est plus impliqué. Toute communication ultérieure est pair-à-pair.

🖧 Étape 2 — Négociation ICE et traversée NAT

La plupart des appareils se trouvent derrière un routeur utilisant la NAT (Network Address Translation), ce qui signifie qu’ils n’ont pas d’adresse IP publique à laquelle un autre appareil peut se connecter directement. WebRTC résout ce problème via un processus appelé ICE (Interactive Connectivity Establishment).

Serveurs STUN

Chaque navigateur contacte un serveur STUN (Session Traversal Utilities for NAT) pour découvrir sa propre adresse IP publique et son port tels qu’ils apparaissent depuis internet. Cette adresse publique est incluse dans les candidats ICE envoyés à l’autre pair.

Appariement des candidats

Les deux navigateurs collectent toutes leurs adresses réseau possibles (adresses réseau local, adresses publiques mappées par NAT) et tentent de se connecter à chacune des adresses de l’autre pair en parallèle. La première paire qui réussit devient le chemin de connexion actif.

Relais TURN en secours

Dans certaines configurations réseau (pare-feux stricts, NAT symétrique), les connexions directes ne sont pas possibles. Dans ce cas, WebRTC utilise un serveur TURN (Traversal Using Relays around NAT) comme relais. Même via un relais TURN, les données restent chiffrées DTLS et le serveur relais ne peut pas en lire le contenu.

Expéditeur ↔ [STUN/TURN] ↔ Destinataire
Négociation uniquement — après ICE, les données circulent directement si possible

🔐 Étape 3 — Le canal de données chiffré

Une fois la négociation ICE terminée, WebRTC ouvre un RTCDataChannel entre les deux navigateurs. Ce canal est :

Poignée de main de confirmation de connexion

Avant que le fichier commence à être diffusé, l’application effectue une brève négociation au niveau applicatif :

L’expéditeur envoie : message file-info (nom, taille, type MIME, nombre total de blocs)
Le destinataire répond : message start (identifiant de transfert, premier bloc attendu)
L’expéditeur commence à diffuser les blocs binaires

📦 Étape 4 — Diffusion en blocs

Transférer un fichier volumineux en un seul message binaire surchargerait le tampon d’envoi du navigateur et bloquerait l’interface. Le fichier est donc lu et diffusé en blocs de 64 Ko.

Pourquoi 64 Ko ?

Le RTCDataChannel de WebRTC dispose d’un tampon d’envoi configurable. L’envoi de blocs trop grands peut provoquer un débordement du tampon, entraînant des erreurs ou des coupures. 64 Ko est une taille de bloc conservatrice qui maintient le tampon en dessous de la saturation sur les réseaux typiques tout en offrant un bon débit.

Contrôle du débit

Deux limites maintiennent une consommation mémoire constante. L’expéditeur n’a jamais plus de 16 Mo de blocs non encore confirmés par le destinataire (un bloc est confirmé une fois confié au module d’écriture du destinataire, qui en garde au plus quelques mégaoctets en mémoire avant de les écrire), et il fait une pause dès que la propriété bufferedAmount du canal dépasse 4 Mo, pour reprendre sur l’événement bufferedamountlow. Un réseau ou un disque lent ralentit donc simplement l’expéditeur au lieu de remplir la mémoire.

Suivi de la progression

L’expéditeur et le destinataire suivent la progression en termes de nombre de blocs. Le pourcentage de transfert, la vitesse actuelle (en Ko/s ou Mo/s) et le temps restant estimé sont mis à jour en temps réel à chaque bloc traité.

Écriture sur le disque

Le destinataire ne garde jamais le fichier entier en mémoire. Les blocs sont regroupés par 4 Mo et écrits sur le disque au fur et à mesure : dans Chrome et Edge, directement dans le fichier choisi via une boîte de dialogue affichée avant le début du transfert ; dans Firefox, via un service worker qui les transmet au gestionnaire de téléchargements du navigateur. Les navigateurs ne prenant en charge aucune de ces méthodes (comme Safari) reconstituent le fichier en mémoire et le téléchargent à la fin.

🔄 Étape 5 — Reconnexion et reprise

Les connexions réseau ne sont pas toujours fiables — un téléphone passant du Wi-Fi au réseau cellulaire, un ordinateur portable se mettant en veille, ou une brève panne de routeur peut couper la connexion WebRTC en cours de transfert. File Transfer gère cela automatiquement.

Détection

Une connexion coupée ne se ferme pas toujours proprement : WebRTC peut rester indéfiniment dans l’état « disconnected ». Les deux côtés envoient donc un signal de vie toutes les 5 secondes, et une connexion silencieuse pendant 20 secondes est considérée comme perdue, au même titre qu’une connexion fermée. La connexion au serveur de signalisation, nécessaire pour se reconnecter, est elle aussi rétablie automatiquement si elle tombe.

Fenêtre de reconnexion

Un compte à rebours de 60 secondes commence. Pendant cette fenêtre :

Reprise depuis un point de contrôle

Lorsque le destinataire se reconnecte, il envoie un message start avec son identifiant de transfert et le nombre exact de blocs déjà reçus. L’expéditeur reconnaît le transfert, même s’il n’avait pas encore remarqué la coupure de son côté, et reprend la diffusion à partir de cet index. Aucune donnée n’a besoin d’être retransférée depuis le début.

Connexion interrompue au bloc 1 450 sur 2 000
Le destinataire se reconnecte et envoie : { type: "start", rxId: "…", from: 1450 }
L’expéditeur reprend au bloc 1 451 — aucune donnée n’est renvoyée

🚫 Ce que nous ne voyons jamais

Comme toutes les données de fichiers circulent directement entre les navigateurs dans un canal chiffré, les informations suivantes ne sont jamais accessibles par nous ni par le serveur de signalisation PeerJS :

Les seules données qui passent par les serveurs PeerJS sont les messages initiaux de négociation SDP et ICE, qui contiennent des adresses réseau mais aucune donnée de fichier. Ces messages sont éphémères et ne sont pas journalisés.

Qu’en est-il des relais TURN ?

Dans de rares cas où une connexion directe ne peut pas être établie, les données peuvent transiter par un serveur relais TURN. Les serveurs TURN voient des paquets chiffrés mais ne peuvent pas les déchiffrer — le chiffrement DTLS est de bout en bout entre les deux navigateurs, indépendamment du chemin relayé.

📖 Résumé

Voici la séquence complète du début à la fin :

  1. L’expéditeur sélectionne un fichier ; l’application génère un identifiant pair UUID aléatoire.
  2. Le navigateur de l’expéditeur enregistre l’UUID auprès du serveur de signalisation PeerJS.
  3. L’expéditeur partage avec le destinataire un lien contenant l’UUID (par n’importe quel moyen).
  4. Le destinataire ouvre le lien et accepte le transfert ; les deux navigateurs échangent SDP et candidats ICE via le serveur de signalisation.
  5. La négociation ICE trouve le chemin réseau optimal (direct si possible, via TURN sinon).
  6. Un RTCDataChannel chiffré est ouvert entre les deux navigateurs.
  7. L’expéditeur transmet les métadonnées du fichier ; le destinataire confirme qu’il est prêt.
  8. Le fichier est lu et diffusé en blocs de 64 Ko via le canal de données.
  9. Le destinataire écrit les blocs sur le disque au fur et à mesure (ou les assemble en mémoire sur les navigateurs qui ne le permettent pas).
  10. Si la connexion est interrompue, les deux côtés tentent de se reconnecter et de reprendre à partir du dernier bloc reçu.

Pour plus de contexte sur les objectifs du projet et la philosophie de confidentialité, consultez la page à propos.