[Python] Socket

Roberto De Ioris roberto a unbit.it
Ven 15 Lug 2011 08:53:11 CEST


Il giorno 15/lug/2011, alle ore 08.37, Simone Ziraldo ha scritto:

>> il fatto che sia wi-fi è un dettaglio implementativo, fosse via cavetto ethernet il discorso sarebbe esattamente lo stesso
>> (scusa è che se no sembra che le socket abbiano a che fare esclusivamente con le connessioni wi-fi quando invece sono un astrazione moolto più generale generale)
> si si, era solo per fare un esempio pratico di come ottengo il problema.
> 
>> venendo al tuo problema: non mi risulta che sia possibile, per risolvere un problema simile costringevo il client a mandarmi un pachetto di acknowledge entro tot secondi
>> 
>> in pratica il ruolo di tale pacchetto era esclusivamente quello di segnalare "sono ancora vivo"
>> 
>> se il server non riceveva dati o acknowledge entro tot tempo assumeva che il client fosse morto e chiudeva la socket
> ci avevo pensato ma il problema è che il server rimane fermo su s.recv quando cade la connessione e quindi non posso fare altre comunicazioni...
> 
> Le soluzioni che mi vengono in mente in questo momento sono due:
> 1) fare un socket.accept prima di ogni socket.recv, in questo modo avrei maggiore probabilità di avere una connessione funzionante per il recv
> 2) mandare il comando socket.recv in un thread separato, e nel main controllo quanto tempo ci impiega. Se passano troppi secondi allora la connessione o è troppo lenta o è caduta e quindi posso "uccidere" il recv  e procedere con un nuovo socket.accept.
> 
> La prima soluzione potrebbe rallentare lo scambio dati e, anche se con minor probabilità, potrebbe presentare lo stesso problema iniziale. La seconda soluzione mi sembra un po' più generica ma non so se sia implementabile...
> 
> Forse il mio stupore è dovuto alla mia ignoranza, ma mi stupisce che pur settando un timeout finito il comando recv non va in timeout quando c'è una caduta improvvisa della connessione...
> 

ignoranza e' una parola grossa, soprattutto nel nostro settore, ma di sicuro i socket sono una componente cosi' importante dell'informatica che conoscerli un po' meglio non farebbe male :)

Comunque non mi dilungo in teoria, e ti spiego direttamente come fare.

Hai bisogno (prima di read/recv) di sapere se c'e' qualcosa nel socket (se c'e' allora la chiamata successiva non sara' bloccante).

Per farlo hai le funzioni di sistema select/poll e il loro equivalente ultra-fico-mega-scalabile-nonstandard epoll/kqueue/port (in base al sistema operativo su cui sei)

Io ti consiglio di partire con poll() che e' la piu' semplice di tutte.

Quindi l'approccio e':

1) fai una chiamata a poll() passandogli il filedescriptor a cui sei interessato (il socket) e il timeout.
2) se poll() restituisce 0 c'e' stato il timeout e allora chiudi la connessione e addio
3) se restituisce >0 allora ci sono dati nel socket e puoi leggerli tranquillamente senza paura di bloccare tutto

poll e' gestita in python da questo modulo:

http://docs.python.org/library/select.html

qui ci sono un bel po' di esempi:

http://www.doughellmann.com/PyMOTW/select/

--
Roberto De Ioris
http://unbit.it



Maggiori informazioni sulla lista Python