Type de téléchargement de partage HTTP réalisé avec Python

Déclencheur

――J'ai fait un contrat pour la ligne optique de ma maison à 1 Gbps, mais quand j'ai essayé de télécharger un gros fichier (ISO de Linux) etc. par HTTP, la vitesse n'est pas sortie

Pourquoi?

--Il existe une limite au débit qui peut être généré avec une seule connexion TCP. --Comment vérifier ~~ Taille de la fenêtre de réception TCP ~~ pour Linux (pour être exact, la taille du tampon du noyau)

$cat /proc/sys/net/ipv4/tcp_rmem
4096    87380   6291456

À partir de la gauche [min, default, max]

Ainsi, le débit maximum est

T_{max} = win / RTT

Par conséquent, s'il s'agit d'une connexion TCP unique, la communication avec un serveur avec RTT = 30ms dans l'état par défaut ~~ Environ 87380 [octets] * 8/30 [ms] ≒ 23,3 [Mbps] uniquement ~~ En fait, ** s'il n'y a pas de congestion **, la taille de la fenêtre deviendra de plus en plus grande, donc elle sera plus rapide.

Bien sûr, TCP a une option à l'échelle de la fenêtre pour prendre en charge les réseaux à large bande. La taille de la fenêtre peut être étendue jusqu'à 1 Go (on ne sait pas si elle est réellement utilisée)

En théorie, s'il y a plusieurs connexions, la bande sera N fois plus grande que N faisceaux.

Outils existants

Wget et curl sont connus comme des outils qui peuvent être utilisés à partir de la ligne de commande Il y a aria2 etc. qui peuvent utiliser plusieurs connexions Utilisez le téléchargeur explosif aria2, qui est plusieurs fois plus rapide que curl et wget --Qiita Lors de l'établissement de plusieurs connexions, ne surchargez pas l'autre serveur

Créer un client HTTP pour le sujet

HTTP a une requête de plage RFC 7233 - HTTP / 1.1: Requêtes de plage La mise en œuvre est en Python populaire pour le moment

À propos de la demande de gamme

--Par exemple, supposons que vous demandiez un fichier de 1000 octets --Lors de l'envoi d'une requête GET avec 'Range: bytes = 0-499' dans l'en-tête, --Add'Content-Range: octets 0-499 / 1000 'à l'en-tête de réponse et ne renvoie que les 500 premiers octets du fichier dans le corps.

Cependant, dans certains cas, le serveur n'accepte pas les en-têtes Range.

Utilisez cette fonctionnalité pour demander différentes parties d'un fichier à partir de plusieurs connexions TCP en même temps

Multiplexage

Python a un module appelé sélecteurs qui peut gérer certains appels système à un niveau supérieur (dans la bibliothèque standard!) 18.4. Sélecteurs - Haut niveau de multiplexage d'E / S - Documentation Python 3.6.1 Surveillez et multiplexez plusieurs prises avec ce gars Utilisez comme ça

#Imaginez une connexion avec deux serveurs d'écho TCP, A et B
import selectors
import socket

#Omission
sel = selectors.DefaultSelectors()
sock_A = socket.create_connection(address_A)
sock_B = socket.create_connection(address_B)

sel.resister(sock_A, selectors.EVENT_READ)
sel.resister(sock_B, selectors.EVENT_READ)


sock_B.sendall('Hello'.encode()) # send something to A
sock_B.sendall('Hello'.encode()) # send something to B

while True:
    events = sel.select()
    for key, mask in events:
        message = key.fileobj.recv(512)
        print(message.decode())

point

Écoulement brutal

  1. Envoyez une requête HTTP HEAD pour vérifier la taille du fichier (cela utilise une bibliothèque HTTP existante)
  2. Déterminez le nombre total de divisions et la taille de la division, puis établissez une connexion
  3. Envoyez la demande initiale
  4. Surveillez les sockets avec les sélecteurs mentionnés ci-dessus, lisez séquentiellement les sockets qui sont devenus lisibles et placez chaque socket dans le tampon principal.
  5. Lorsque le contenu du tampon principal est suffisamment long pour être traité comme une réponse HTTP, divisé en un en-tête et un corps
  6. Identifiez la partie du fichier à laquelle la réponse correspond à partir de l'en-tête et passez du tampon principal au tampon secondaire
  7. Écrire dans le fichier à partir du premier dans le tampon secondaire, puis supprimer du tampon secondaire
  8. Mettez à jour la valeur d'évaluation de chaque connexion, supprimez la connexion jugée faible et renvoyez la demande à la connexion nouvellement établie.
  9. Répétez les étapes 4 à 8 jusqu'à ce que le fichier entier soit complet

Mis en œuvre

https://github.com/johejo/rangedl Il y a encore quelques bugs

Comment utiliser

Environnement Python 3.6.1

$ pip install git+http://github.com/johejo/rangedl.git
$ rangedl [URL] -n [NUM_OF_CONNECTION] -s [SPLIT_SIZE_MB]

résultat

――Selon l'humeur de la ligne, j'ai pu télécharger à environ 200 Mbps. --Lorsque split_size est défini sur 1 Mo, l'utilisation de la mémoire est d'environ 30 à 80 Mo. Est-il inévitable que l'utilisation du processeur soit élevée ...

Recommended Posts

Type de téléchargement de partage HTTP réalisé avec Python
Communication HTTP avec Python
J'ai fait un blackjack avec du python!
Serveur HTTP facile avec Python
J'ai fait un blackjack avec Python.
Othello fait avec python (comme GUI)
J'ai créé wordcloud avec Python.
Télécharger le fichier csv avec python
Bases de SNS Python faites avec Flask
Téléchargement de fichiers implémenté avec Python + Bottle
Numer0n avec des objets fabriqués avec Python
J'ai fait une loterie avec Python.
Développement de jeux Othello avec Python
J'ai créé un démon avec Python
Télécharger Python
Lire le fichier CSV avec python (Télécharger et analyser le fichier CSV)
Client API Slack simple réalisé avec Python
J'ai fait un compteur de caractères avec Python
Téléchargez les données de cours des actions japonaises avec Python
Télécharger des fichiers sur le Web avec Python
J'ai fait une carte hexadécimale avec Python
Téléchargez facilement des mp3 / mp4 avec python et youtube-dl!
API de reconnaissance faciale sans serveur conçue avec Python
J'ai fait un jeu rogue-like avec Python
J'ai fait un simple blackjack avec Python
J'ai créé un fichier de configuration avec Python
J'ai fait un simulateur de neurones avec Python
Application Othello (application iOS) réalisée avec Python (Kivy)
Diviser le fichier mol2 avec python (-> 2016.04.17 prend également en charge le fichier sdf)
[Python] Python et sécurité-② Outil d'analyse de port réalisé avec Python
FizzBuzz en Python3
Rechercher et télécharger automatiquement des vidéos YouTube avec Python
Grattage avec Python
J'ai fait une prévision météo de type bot avec Python.
Statistiques avec python
J'ai créé une application graphique avec Python + PyQt5
Grattage avec Python
Python avec Go
Contenu Web Python réalisé avec le serveur bon marché Lolipop
Outil de rognage d'image GUI réalisé avec Python + Tkinter
J'ai essayé de créer un bloqueur de filles pourries sur Twitter avec Python ①
Twilio avec Python
Procédure de création d'un LineBot réalisé avec Python
Intégrer avec Python
Jouez avec 2016-Python
[Python] J'ai créé un téléchargeur Youtube avec Tkinter.
AES256 avec python
Testé avec Python
python commence par ()
avec syntaxe (Python)
Bingo avec python
Zundokokiyoshi avec python
Télécharger en masse des images à partir d'une URL spécifique avec python
Envoyer HTTP avec l'en-tête d'authentification de base en Python
Excel avec Python
Micro-ordinateur avec Python
J'ai fait un jeu de cueillette avec Python
Made Mattermost Bot avec Python (+ Flask)
Cast avec python
J'ai fait un Twitter BOT avec GAE (python) (avec une référence)