2009-07-08 6 views
7

Ho bisogno di svuotare i dati su un socket (assicurandomi che non ci sia nulla da ricevere). Sfortunatamente, non c'è alcuna funzione per questo nel modulo socket python.Come svuotare un socket in python?

Ho implementato qualcosa in questo modo:

def empty_socket(sock): 
    """remove the data present on the socket""" 
    input = [sock] 
    while 1: 
     inputready, o, e = select.select(input,[],[], 0.0) 
     if len(inputready)==0: break 
     for s in inputready: s.recv(1) 

Cosa ne pensi? C'è un modo migliore per farlo?


Aggiornamento: non desidero modificare il timeout del socket. Qual è il motivo per cui preferisco una selezione a una lettura.


Aggiornamento: la domanda originale utilizzava il termine 'flush'. Sembra che "vuoto" sia un termine migliore.


Update - 2010-02-27: ho notato un bug quando la coppia ha chiuso. L'inputready è sempre pieno delle prese. Ho risolto questo aggiungendo un numero massimo di loop. C'è una soluzione migliore?

+0

questo non è proprio un "flush" per dire. Dai un'occhiata agli esempi nella documentazione per leggere un socket. http://docs.python.org/library/socket.html#example – JimB

+1

Hai mai pensato di utilizzare Twisted per il tuo programma? Se lo facessi, non avresti mai bisogno di fare nulla di simile. Twisted estrae immediatamente tutti i dati dallo zoccolo e lo recapita a voi ogni volta che arriva, quindi non c'è bisogno di scherzare con dettagli brutti come il problema select() descritto dalla risposta di Thomas qui sotto. – Glyph

+0

@Glyph: No Non ho considerato Twisted perché volevo usare il modulo standard python per evitare dipendenze esterne. Grazie per questo commento, vedrò Twisted e forse riconsidererò la mia scelta. – luc

risposta

6

Se con "flush" si intende eliminare tutti i dati in attesa in sospeso, è possibile utilizzare select() come si fa o impostare il socket su nonblocking e leggere in un loop finché non si esauriscono i dati.

Si noti inoltre che (dalla pagina di manuale di Linux):

Sotto Linux, select() può segnalare un descrittore di file presa come "pronto per la lettura", mentre comunque un successivi blocchi di lettura. Questo potrebbe per esempio accadere quando i dati sono arrivati ​​ma sull'esame ha checksum errato e viene scartato. Potrebbero esserci altre circostanze in cui un descrittore di file viene falsamente segnalato come pronto. Pertanto potrebbe essere più sicuro utilizzare O_NONBLOCK sui socket che non dovrebbero essere .

Spurious readiness notification for Select System call

E come è stato già sottolineato da altri, "flush" di solito si riferisce all'uscita.

+1

Quale sarebbe il termine giusto per "irrigare" un input? Grazie per la tua risposta – luc

+0

Personalmente, chiamerei quello che stai facendo "svuotando" il socket. Anche se mi sembra strano il motivo per cui vorresti farlo, qualcuno ti ha mandato quei dati per una ragione, perché stai buttando via tutto senza elaborarlo? :) – Glyph

+0

non possiamo semplicemente fare un recv con len per leggere come 0 dopo i resi selezionati? –

-1

Non sono sicuro se questo funzionerà, ma si potrebbe allegare un oggetto file di descrittore di file del socket e chiamare il metodo flush() su quella oggetto file:

import os 

file_obj = os.fdopen(your_socket.fileno()) 
file_obj.flush() 

Questo non funziona in Windows perché il descrittore restituito da fileno() non può essere passato a os.fdopen() in Windows

+0

a livello di oggetti file svuota solo l'output memorizzato nella cache in userspace. Confronta FILE * in C e fflush. Di solito, l'I/O socket raw non viene memorizzato nel buffer e, se è presente, non viene memorizzato nel buffer in userspace e un'operazione simile a fflush non funzionerà. Si consiglia di guardare "push" per TCP. – Thomas

1

L'utilizzo di select.select è una buona pratica, come indicato nello Socket Programming HOWTO. È necessario impostare il socket come non bloccante, utilizzando sock.setblocking(0).

Solo un commento sulla nomenclatura: flush è normalmente associato alle operazioni in uscita.

1

Per i pacchetti UDP, ho fatto la seguente:

  1. Dopo aver creato il socket, l'impostazione delle opzioni, e vincolante, io uso socket.settimeout(). Notare che la documentazione per setblocking() fornisce alcune informazioni che non corrispondono a settimeout() - se si desidera bloccare le operazioni di socket, è sufficiente utilizzare settimeout() per impostare il timeout. setblocking() mette solo un timeout infinito su di esso. (Ho avuto un bug chiamando settimeout() seguito da setblocking(1).)

  2. mio "tampone svuotamento" funzione è quindi solo questo ("Listener" è la mia presa):

    def FlushListen(self): while 1: try: PacketBytes = self.__Listener.recv(1024) except: break;

    con un timeout di 1 in secondo luogo, questo leggerà tutti i pacchetti UDP e quindi restituirà 1 secondo dopo che non ci sono dati.

Nel mio caso io sto usando per parlare solo tra due programmi sullo stesso PC in modo da poter facilmente abbassare il mio timeout ma la velocità non è un problema così sto bene con questo.

Secondo alcuni dei link pubblicati da altri, questo dovrebbe funzionare anche con i flussi di dati.

0

Non possiamo continuare a leggere finché il buffer non è vuoto?

def clear_buffer(sock): 
    try: 
     while sock.recv(1024): pass 
    except: 
     pass