[Python] socket - questa me la dovete proprio spiegare..

Manlio Perillo manlio_perillo a libero.it
Lun 30 Lug 2007 09:57:16 CEST


allanon ha scritto:
> Eccomi qua, con un altro quesito!
> 
> siccome sono niubbo il codice lo provo prima nell'interprete ide
> (quello che si lancia scrivendo python da console :p)
> 
> e allora scrivo questo codice qui
> 
> #!/usr/bin/python
> import sys
> from socket import *
> import re
> Host = 'localhost'
> Port = 5038
> s = socket(AF_INET, SOCK_STREAM)
> s.connect((Host, Port))
> s.send('Action: Login\r\nUserName: fop\r\nSecret: didodidodee\r\n\r\n')
> s.send('Action: Command\r\nCommand: Show Channels\r\n\r\n')
> data = s.recv(2048)                 # riceve fino a  2K bytes
> rawstr = r"""\d(?=.active channels)"""
> d=re.findall(rawstr,str(data))
> print "canali attivi "+str(d)
> 
> e funziona senza dire pio!
> mi ritorna
> 
> [...]
> [Protocollo basato su scambio di messaggi]
> 
> 
> 
> 
> Quanto invece lo stesso identico e medesimo codice frutto del copia e
> incolla piu' puro lo ficco dentro un file e lo eseguo..
> # ./prova-asterisk.py 
> canali attivi []
> 
> e la variabile data
> contiene soltanto
> 
> Asterisk Call Manager/1.0
> 
> 
> 
> secondo voi, come e' possibile che lo stesso codice ha un comportamento
> differente??
> 
> PS
> sono arcisicuro che mi manca qualche dettaglio essensiale,
> daltra parte non potrebbe essere altrimenti,
> pero stavolta sono propro curioso di sapere cosa e' 
> 

Il dettaglio essenziale che ti manca è sapere come funzionano i socket.

Se leggi la documentazione del modulo socket, puoi notare un:
"""The maximum amount of data to be received at once is specified by 
bufsize"""

Questo significa che, nel tuo caso otterrai *al massimo* 2048, ma nulla 
vieta di ottenere molto meno.

Tutto dipende da quanto dati sono disponibili nel buffer interno dei socket.

Per questo il tuo amico ti ha consigliato un timer, attendi finchè 
*presumi* il server ti abbia mandato tutto.

E' chiaro che è una soluzione assolutamente sbagliata...


Hai due soluzioni:
1) Leggere la risposta linea per linea.
2) Leggere tutta, ma proprio tutta, la risposta

In entrambi i casi la soluzione più semplice è usare
sock.makefile('rb', 0)

Vedi ad esempio l'implementazione del modulo httplib.

Per leggere una linea alla volta basta fare fp.readline(), per leggere 
tutta la risposta, basta un fp.read()


Attenzione, che se usi fp.read(), stai assumendo che il server chiuda la 
connessione dopo aver spedito tutti i dati, altrimenti non hai modo di 
sapere quando devi smettere di leggere.

Se leggi linea per linea, invece, magari puoi intercettare ed 
interpretare un eventuale header Content-Lenght, come succede in
HTTP 1.1.



Saluti  Manlio Perillo


Maggiori informazioni sulla lista Python