[HTTP-CLIENT] - RÉCUPÉRER UNE REQUETE COMPLÈTE SANS PASSER PAR LES SOCKETS ASYNC

Messages postés
333
Date d'inscription
dimanche 25 mai 2003
Statut
Membre
Dernière intervention
23 novembre 2009
- - Dernière réponse : cs_jean84
Messages postés
450
Date d'inscription
jeudi 26 août 2004
Statut
Membre
Dernière intervention
5 mars 2009
- 30 juin 2007 à 11:14
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/43283-http-client-recuperer-une-requete-complete-sans-passer-par-les-sockets-asynchrones

Afficher la suite 
cs_jean84
Messages postés
450
Date d'inscription
jeudi 26 août 2004
Statut
Membre
Dernière intervention
5 mars 2009
-
Hello ;-)

Ok je viens de saisir pour le pseudo fichier. Je vais tester et je te tiens au courant.

Merci :-p
cs_Dobel
Messages postés
333
Date d'inscription
dimanche 25 mai 2003
Statut
Membre
Dernière intervention
23 novembre 2009
-
oups, oui, tu bosses côté client.
(c'est ça de poster aussi "tôt" un weekend :))

Enfin, c'est la même chose.

tu peux aussi créer des pseudos fichiers avec makefile,
en lecture et/ou en écriture suivant les arguments
(wfile = sock.makefile("wb", 0) par exemple pour un pseudo fichier en écriture)

pour HTTP 0.9 :
tu lis tant que tu peux, cad juste la méthode read du pseudo fichier, sans donner d'argument size, qui lira jusqu'à EOF

pour les autres,
tu lis ligne par ligne la version, code réponse, etc., puis les entêtes jusqu'à trouver une ligne blanche
et tu peux utiliser le champ content-length si il est là, ou sinon, tu lis aussi jusqu'au bout.

bonne prog.
cs_Dobel
Messages postés
333
Date d'inscription
dimanche 25 mai 2003
Statut
Membre
Dernière intervention
23 novembre 2009
-
ok.
j'espère que ce que je vais dire est juste, j'ai jamais testé et :)


autant que je sache, la méthode readline qu'ils ont fait utilise son buffer pour faire abstraction des trames TCP.
ça doit être un truc du genre :
recv, regarde si il y a un \n (LF) dedans, si oui, coupe au \n, retourne la 1ère partie, conserve la 2nde
sinon, recv à nouveau.

donc 1er readline : commande HTTP, chemin, version
readlines suivant : tous les entêtes, jusqu'à rencontrer une ligne vide

puis lecture du corps de la requête (là, ça va dépendre de la version d'HTTP)


pour le test if not data: break,
il semble que quand le client ferme sa socket, recv retourne "", un paquet vide.
si tu ne gères pas les connexions persistantes, ça doit être bon.

ça doit fonctionner quelque soit le nombre de trames utilisées par le client :)


"car on veut éviter de faire appel à cette fonction si on n'a plus rien à recevoir (et donc éviter qu'elle attende dans le vide)"
=> d'où l'intérêt d'utiliser des threads, pour ne plus avoir cette limitation :)
t'attends que ton client ferme tranquillement sa socket, et hop. ton thread gérant la requête se termine.
cs_jean84
Messages postés
450
Date d'inscription
jeudi 26 août 2004
Statut
Membre
Dernière intervention
5 mars 2009
-
Salut

Je pense que tu m'as mal compris. Le code que tu présentes est celui d'un serveur (fonction bind()) qui ne doit recevoir effectivement que des requêtes, d'où l'intérêt de n'arriver qu'à \r\n (HTTP 1.1).
Mon problème ce positionne côté client : dans le cas d'un forward en HTPP, il est beaucoup plus pratique de recevoir toutes les données (réponse serveur + contenu de la page demandée) pour les renvoyer en intégralité au proxy suivant (que j'ai développé). Je laisse le soin à python (et à TCP) de fragmenter les trames pour ses besoins, je n'ai besoin de travaillé pour ma part qu'avec les données complètes, fragmenter les paquets HTTP devient ensuite un casse tête à gérer(encore une fois, pour mon projet).

Des expériences que j'ai réalisé, beaucoup de serveur envoi leurs entêtes dans un paquet différent de celui du contenu des pages. On peut palier ce problème en réservant un buffer plus important mais on fini par se retrouver avec des entêtes et une partie de la page HTML dans un buffer. Suivant le site, on peut essayer de 'prévoir' la taille du buffer en réception mais je ne trouve pas cela très propre et il existera toujours des exceptions (on ne peut pas connaitre à l'avance la taille que fera un site).
Je me suis basé ensuite sur le champ content-lenght mais la encore, chaque serveur fait sa sauce (suivant sa configuration essentiellement et sa façon d'implémenter le protocole HTTP) et n'envoi pas toujours ce param (ça faciliterai beaucoup de choses pourtant :^) )
J'ai trouvé ensuite plusieurs astuces ici et là mais aucune d'entre elles n'a fonctionné (je m'y suis peut être pris comme un manche, c'est possible aussi) :
- le site du zéro indique de tester le retour de recv() avec not (un peu comme tu l'as fait). Sur de nombreux forum, j'ai pu lire que cela ne fonctionne pas et ce pour une simple raison, c'est qu'on teste le buffer de sortie après l'appel a recv(), donc inutile car on veut éviter de faire appel à cette fonction si on n'a plus rien à recevoir (et donc éviter qu'elle attende dans le vide)
- progx.org donne une solution à ce problème grâce à la fonction socket.setblocking(0). Pour mon utilisation, cela n'a pas fonctionné car apparemment il faut que les communications soient absolument synchrone (au centième de seconde près). Il faut que le paquet à recevoir arrive au moment ou python exécute la fonction sinon elle passe par le try: except: et le paquet est rejeté (ou du moins, il n'est pas pris en compte)
- une dernière solution concerne les threads. Pas utile dans mon cas car je veux garder la synchronisation du serveur et du client : l'un envoi, l'autre reçoit puis envoi à son tour etc...
Même si le protocole HTTP 1.1 gère les envois multiples d'entêtes sans attendre le retour, ce ne faisait pas parti de mon cahier des charges. Je n'ai pas besoin d'envoyer et recevoir en même temps donc j'ai préféré zappé (bien que l'implémentation des threads en python soit excessivement simple, c'est indéniable)

C'est donc après mes petites recherches que j'en suis arrivé à ce code. Je le dis je le répète, je suis nouveau en python. Il est évident que j'ai du passer à coté de quelque chose mais n'ayant pas trouvé de solution probante, j'ai du me résoudre à l'obtenir par mes propres moyens.

Merci de m'avoir lu jusque là et si j'ai dit une bêtise, merci de me le signaler ;-)

++
cs_Dobel
Messages postés
333
Date d'inscription
dimanche 25 mai 2003
Statut
Membre
Dernière intervention
23 novembre 2009
-
Pour info, les objets sockets en python contiennent déjà de quoi faire ce genre de lecture.
tu as une méthode makefile pour créer des objets type fichier, qui travaille sur des buffers.

s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()

# pseudo fichier en lecture, binaire, buffer taille par défaut du système
rfile = conn.makefile('rb', -1)

while 1:
data = rfile.readline()
if not data: break
print data

readline retourne bien la chaîne jusqu'au premier \n rencontré, et non pas juste à la fin de ce que te retourne recv