2010-04-03 7 views
1

Je construis un gestionnaire de téléchargement en python pour le fun, et parfois la connexion au serveur est toujours active mais le serveur ne m'envoie pas de données, donc read method (de HTTPResponse) bloque moi pour toujours. Cela se produit, par exemple, lorsque je télécharge à partir d'un serveur, situé en dehors de mon pays, qui limite la bande passante à d'autres pays.set timeout to http réponse méthode de lecture en python

Comment puis-je définir un délai pour la méthode de lecture (2 minutes par exemple)?

Merci, Nir.

+0

liée: [Lire le délai d'expiration en utilisant urllib2 ou toute autre bibliothèque http] (http://stackoverflow.com/q/9548869/4279) – jfs

Répondre

2

Vous devez le définir pendant l'initialisation HTTPConnection.

Remarque: si vous utilisez une ancienne version de Python, vous pouvez installer httplib2; par beaucoup, il est considéré comme une alternative supérieure à httplib, et il prend en charge timeout.
Je ne l'ai jamais utilisé, cependant, et je ne fais que rapporter ce que la documentation et les blogs disent.

+0

+1, mais notez que le paramètre timeout du constructeur est disponible uniquement en python 2.6 +. –

+0

Droite - J'ai ajouté quelques notes à propos de httplib2 –

+0

Je vais essayer, mais je suis un peu sceptique parce que le code de la classe HTTPResponse utilise la méthode 'makefile', qui ne peut pas obtenir un timeout par la documentation: "Le socket doit être en mode blocage (il ne peut pas avoir de délai) ". – user164524

3

Si vous êtes coincé sur une version Python < 2.6, une approche (imparfaite mais utilisable) est de faire

import socket 
socket.setdefaulttimeout(10.0) # or whatever 

avant de commencer à utiliser httplib. Les documents sont here et indiquent clairement que setdefaulttimeout est disponible depuis Python 2.3 - chaque socket créée à partir du moment où vous faites cet appel, jusqu'au moment où vous appelez la même fonction, utilisera ce délai de 10 secondes. Vous pouvez utiliser getdefaulttimeout avant de définir un nouveau délai, si vous souhaitez enregistrer le délai précédent (y compris aucun) afin de pouvoir le restaurer plus tard (avec un autre setdefaulttimeout). Ces fonctions et idiomes sont très utiles lorsque vous avez besoin d'une ancienne bibliothèque de plus haut niveau qui utilise Python socket s mais ne vous donne pas un bon moyen de définir des délais d'attente (bien sûr, il est préférable d'utiliser mise à jour de plus haut niveau bibliothèques, par exemple la version httplib qui vient avec 2.6 ou le tiers dans ce cas, mais ce n'est pas toujours possible, et jouer avec le paramètre de délai d'attente par défaut peut être une bonne solution de contournement).

1

Si vous définissez le délai d'attente par défaut, vous risquez d'interrompre prématurément un téléchargement si celui-ci est volumineux, par opposition à un abandon uniquement s'il arrête de recevoir des données pour la valeur du délai d'expiration. HTTPlib2 est probablement le chemin à parcourir.

-1

5 ans plus tard, mais nous espérons que cela aidera quelqu'un d'autre ...

Je détruisait mon cerveau en essayant de comprendre. Mon problème était un serveur qui retournait du contenu corrompu et qui restituait donc moins de données qu'il ne le pensait. Je suis venu avec une solution désagréable qui semble fonctionner correctement. Ici, il va:

# NOTE I directly disabling blocking is not necessary but it represents 
# an important piece to the problem so I am leaving it here. 
# http_response.fp._sock.socket.setblocking(0) 
http_response.fp._sock.settimeout(read_timeout) 
http_response.read(chunk_size) 

NOTE Cette solution fonctionne également pour les demandes pythonQUELQUE bibliothèque qui implémente les prises de python normales (qui devraient être tous?).Il vous suffit d'aller quelques niveaux plus profonds:

resp.raw._fp.fp._sock.socket.setblocking() 
resp.raw._fp.fp._sock.settimeout(read_timeout) 
resp.raw.read(chunk_size) 

A ce jour, je ne l'ai pas essayé ce qui suit, mais en théorie il devrait fonctionner:

resp = requests.get(some_url, stream=True) 
resp.raw._fp.fp._sock.socket.setblocking() 
resp.raw._fp.fp._sock.settimeout(read_timeout) 
for chunk in resp.iter_content(chunk_size): 
     # do stuff 

Explication

I tombé sur cette approche lors de la lecture de cette question SO pour setting a timeout on socket.recv

À la fin de la journée, toute demande http a une prise. Pour le httplib, cette socket est située à resp.raw._fp.fp._sock.socket. Le resp.raw._fp.fp._sock est un socket._fileobj (que honnêtement je n'ai pas regardé loin dans) et j'imagine que c'est la méthode settimeout le place en interne sur l'attribut socket.

+1

Si vous allez downvote une réponse au moins donner un gars une raison. – Realistic