Forum Programmation.shell astuce : wget trop lent, axel prend le relai

Posté par . Licence CC by-sa
Tags :
10
18
mar.
2016

Le problème

Un fichier archive à télécharger, premier réflexe :

wget http://url/vers/mon/fichier

Et au bout que quelques minutes se dire : "Zut, il est gros ce fichier et c'est lent, ça ne sature même pas mon lien ADSL…"

Second réflexe : j'aurai dû utiliser axel.

Dilemme, je kill le wget en cours et relance avec axel ? Dommage pour tous ces octets qui ont déjà fait un si long voyages.

Si je pouvais dire à axel que wget a déjà fait un gros bout du travail, il pourrait prendre la suite au lieu de tout recommencer.

L'idée

Axel dump régulièrement un fichier d'état pour pouvoir reprendre le téléchargement si il est interrompu.

Est ce que je ne peux pas construire ce fichier à partir de ce qu'a déjà téléchargé par wget ? réponse : si, avec le script disponible ici.

Le script n'utilise que bash, coreutils et axel. Et implicitement dépend du format interne du fichier d'état de axel qui n'est pas dans un format standard mais reste très simple.

Comment ?

Pour rappel, axel découpe le travail en morceaux de taille équivalente et lance une connexion HTTP par morceau en utilisant l'option "range" de HTTP.

Le format du fichier d'état est le suivant:

nombre de connexions simultanées (int)
octets déjà téléchargés (long)
où j'en suis sur la 1ère connexion (long)
où j'en suis sur la 2ème connexion (long)
...
où j'en suis sur la Nème connexion (long)

Il ne manque qu'une donnée de départ : la taille totale du fichier à télécharger.
Le script lance axel une première fois pour récupérer cette information et le kill dans la foulée.
Cela aurai pu être n'importe quel client http mais autant limiter les dépendances.

wget a fait tout le travail pour les premiers morceaux, partiellement pour un d'entre eux et pas du tout pour les derniers.

Si on reprend le fichier d'état, on a donc:

nombre de connexions (int) => 4 (c'est un choix raisonnable)
octets déjà téléchargés (long) => nombre d'octets déjà téléchargés par wget = taille du fichier partiel
où j'en suis sur la 1ère connexion (long) => fini 1/4 taille totale
où j'en suis sur la 2ème connexion (long) => partiel = taille du fichier partiel, compris entre 1/4 et 2/4
où j'en suis sur la 3ème connexion (long) => vide donc 2/4
où j'en suis sur la 4ème connexion (long) => vide donc 3/4

Bien sûr, il y a des variations et il faut faire attention aux cas limites mais l'idée est là. Pour se tromper le moins possible, le script reprend l'algorithme itératif de découpage dans code source d'axel (révision 94 au moment de l'écriture)

Le script embarque une petite optimisation : si on a déjà une bonne partie du fichier (>2/5) autant lancer plus de connexions, sachant que les premières n'ont rien à faire, on va retomber sur le nombre de connexions simultanées voulues.

Conclusion

Finalement, cela se passe comme cela:

wget http://url/vers/mon/fichier
CTRL+C
/path/to/axel_from_wget.sh fichier http://url/vers/mon/fichier
use more connections
Initializing download: http://url/vers/mon/fichier
File size: 41428290 bytes
Opening output file fichier
State file found: 22036480 bytes downloaded, 19391810 to go.
Starting download

Connection 4 finished
[ 63%] [................................5     6     7     ] [   1.3MB/s] [00:10]

Le plus compliqué aura été :

  1. d'écrire des données brutes en bash.
  2. de parvenir à la réflexion qu'il était plus efficace d'utiliser le code source du logiciel plutôt que d'essayer de deviner l’algorithme à partir de données brutes. N'est ce pas tout l'intérêt d'utiliser un produit open source !

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.