2009-07-08 69 views
7

Necesito vaciar los datos en un socket (asegurándome de que no hay nada que recibir). Desafortunadamente, no hay una función para esto en el módulo de socket python.¿Cómo vaciar un socket en python?

he implementado algo así:

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) 

¿Qué le parece? ¿Hay una mejor manera de hacer eso?


Actualización: No deseo cambiar el tiempo de espera del socket. Por eso prefiero seleccionar para leer.


Actualización: La pregunta original estaba usando el término 'flush'. Parece que 'vacío' es un término mejor.


Actualización - 2010-02-27: me he dado cuenta de un error cuando la pareja se ha cerrado. La entrada ya está llena con los sockets. Lo arreglé añadiendo un número máximo de bucles. ¿Hay una mejor solución?

+0

esto no es realmente un "color" por decir. Eche un vistazo a los ejemplos en la documentación para leer un socket. http://docs.python.org/library/socket.html#example – JimB

+1

¿Ha considerado utilizar Twisted para su programa? Si lo hicieras, nunca necesitarías hacer algo como esto. Twisted extraerá inmediatamente todos los datos del socket y se los entregará cada vez que llegue, por lo que no tendrá que preocuparse por detalles desagradables como el problema select() descrito por la respuesta de Thomas a continuación. – Glyph

+0

@Glyph: No, no lo consideré Twisted porque quería usar el módulo de python estándar para evitar dependencias externas. Gracias por este comentario, miraré Twisted y tal vez reconsidere mi elección – luc

Respuesta

6

Si con "flush" quiere decir tirar los datos entrantes pendientes, puede usar select() como lo hace, o establecer el socket en no bloqueo y leer en un bucle hasta que se queden sin datos.

También tenga en cuenta que (desde la página de manual de Linux):

En Linux, seleccione() puede reportar un descriptor de archivo de socket como "listo para la lectura ", mientras que sin embargo un subsiguientes bloques leídos. Esto podría ocurrir, por ejemplo, cuando los datos han llegado, pero al el examen tiene una suma de comprobación incorrecta y se descarta. Puede haber otras circunstancias en las que un descriptor de archivo se informa falsamente como listo. Por lo tanto, puede ser más seguro utilizar O_NONBLOCK en los sockets que no deberían bloquear .

Spurious readiness notification for Select System call

Y como se ha señalado por otros, "vaciar" generalmente se refiere a la producción.

+1

¿Cuál sería el término correcto para "enjuagar" una entrada? Gracias por su respuesta – luc

+0

Personalmente, me gustaría llamar a lo que está haciendo "vaciar" el zócalo. Aunque me parece extraño por qué querrías hacer esto, alguien te envió esos datos por alguna razón, ¿por qué lo tiras todo sin procesarlo? :) – Glyph

+0

¿No podemos hacer un recv con len para leer como 0 después de seleccionar devoluciones? –

-1

No estoy seguro si esto va a funcionar, pero se puede adjuntar un objeto de archivo de descriptor de archivo de la toma y llame al método flush() en ese fichero objeto:

import os 

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

Esto no funcionará en Windows porque el descriptor devuelto por fileno() no se puede pasar a os.fdopen() en Windows

+0

flush on file objects only vacía la salida almacenada en caché en el espacio de usuario. Compare FILE * en C y fflush. La E/S de zócalo sin procesar generalmente no está almacenada en búfer, y si es así, no está almacenada en el espacio de usuario, y una operación similar a flush no funcionará. Es posible que desee ver "push" para TCP. – Thomas

1

usando select.select es una buena práctica, como se indica en el Socket Programming HOWTO. Deberá configurar el socket como no bloqueante, usando sock.setblocking(0).

Solo un comentario sobre la nomenclatura: flush se asocia normalmente con salidas operaciones.

1

Para los paquetes UDP, hice lo siguiente:

  1. Después de crear el zócalo, configurar las opciones, y vinculante, utilizo socket.settimeout(). Tenga en cuenta que la documentación para setblocking() proporciona alguna información que no es la de settimeout(); si desea que las operaciones de su socket se bloqueen, solo debe usar settimeout() para establecer el tiempo de espera. setblocking() simplemente pone un tiempo de espera infinito en él. (Tuve un error llamando settimeout() seguido por setblocking(1).)

  2. Mi "tampón vaciando" función es entonces sólo esto ("escucha" es mi socket):

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

    Con un tiempo de espera de 1 segundo, leerá todos los paquetes UDP y luego regresará 1 segundo después de que no haya datos.

En mi caso lo estoy usando para hablar sólo entre dos programas en el mismo PC, así que podría fácilmente bajar mi tiempo de espera pero la velocidad no es un problema, así que estoy bien con esto.

De acuerdo con algunos de los enlaces publicados por otros, esto debería funcionar también con flujos de datos.

0

¿No podemos seguir leyendo hasta que el buffer esté vacío?

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