2009-10-12 9 views
6

Tengo un cliente que se conecta a una secuencia HTTP y registra los datos de texto que consume.lectura/registro sin bloqueo de una secuencia HTTP

Envío al servidor de transmisión una solicitud HTTP GET ... El servidor responde y publica continuamente datos ... Publicará el texto o enviará un mensaje de ping (texto) regularmente ... y nunca cerrará la conexión.

necesito para leer y registrar los datos que consume en una forma no bloqueante.

que estoy haciendo algo como esto:

import urllib2 

req = urllib2.urlopen(url)  
for dat in req: 
    with open('out.txt', 'a') as f:   
     f.write(dat) 

Mis preguntas son:
será esta vez bloque cuando la corriente es continua?
¿cuántos datos se leen en cada fragmento y se pueden especificar/ajustar?
¿es esta la mejor manera de leer/registrar una secuencia http?

Respuesta

3

Usted está utilizando demasiado alto nivel una interfaz para tener un buen control sobre cuestiones tales como el bloqueo y el tamaño de los bloques de amortiguación. Si no está dispuesto a llegar hasta una interfaz asíncrona (en cuyo caso twisted, ya sugerido, es difícil de superar), ¿por qué no httplib, que después de todo se encuentra en la biblioteca estándar? Es más probable que la instancia de HTTPResponse .read(amount) no se bloquee más de lo necesario para leer amount bytes, que el método similar en el objeto devuelto por urlopen (aunque es cierto que no hay especificaciones documentadas sobre eso en ninguno de los módulos, hmmm ...).

6

¡Eh, eso son tres preguntas en una! ;-)

que podría bloquear a veces - incluso si su servidor está generando datos con bastante rapidez, los cuellos de botella en teoría podrían causar que su lee bloquear.

La lectura de los datos de URL que utilizan "para dat en req" significará la lectura de una línea a la vez - no es realmente útil si usted está leyendo los datos binarios como una imagen. Obtendrá un mejor control si usa

chunk = req.read(size) 

que puede bloquear.

Ya se trate de la mejor manera depende de detalles no disponibles en su pregunta. Por ejemplo, si necesita ejecutar sin llamadas de bloqueo, tendrá que considerar un marco como Twisted. Si no quieres que el bloqueo te retiene y no quieras utilizar Twisted (que es un paradigma completamente nuevo en comparación con la forma de bloquear las cosas), entonces puedes girar un hilo para leer y escribir en archivo, mientras que el hilo principal pasa en su camino feliz:

def func(req): 
    #code the read from URL stream and write to file here 

... 

t = threading.Thread(target=func) 
t.start() # will execute func in a separate thread 
... 
t.join() # will wait for spawned thread to die 

Obviamente, he omitido comprobación de errores/manejo de excepciones, etc., pero es de esperar que sea suficiente para darle la imagen.

1

Sí cuando se pone al día con el servidor, se bloqueará hasta que el servidor produce más datos

Cada dat habrá una línea que incluye el salto de línea en el extremo

torcido es una buena opción

Me gustaría cambiar el y por alrededor de su ejemplo, ¿realmente desea abrir y cerrar el archivo para cada línea que llega?

+0

el pedido de/con fue intencional. esto abrirá/cerrará el identificador del archivo con cada escritura. No es eficiente para una transmisión ocupada, pero en mi caso la transmisión está en su mayoría bloqueada/esperando y ocasionalmente recibe datos para iniciar sesión. –

3

Otra opción es utilizar el módulo socket directamente. Establezca una conexión, envíe la solicitud HTTP, establezca el socket en modo no bloqueante y luego lea los datos con socket.recv() manejando las excepciones 'Resource temporalmente no disponible' (lo que significa que no hay nada que leer). Un ejemplo muy aproximada es la siguiente:

import socket, time 

BUFSIZE = 1024 

s = socket.socket() 
s.connect(('localhost', 1234)) 
s.send('GET /path HTTP/1.0\n\n') 
s.setblocking(False) 

running = True 

while running: 
    try: 
     print "Attempting to read from socket..." 
     while True: 
      data = s.recv(BUFSIZE) 
      if len(data) == 0:  # remote end closed 
       print "Remote end closed" 
       running = False 
       break 
      print "Received %d bytes: %r" % (len(data), data) 
    except socket.error, e: 
     if e[0] != 11:  # Resource temporarily unavailable 
      print e 
      raise 

    # perform other program tasks 
    print "Sleeping..." 
    time.sleep(1) 

Sin embargo, urllib.urlopen() tiene algunos beneficios si el servidor web redirige, necesita la autenticación básica basada URL, etc Usted puede hacer uso del módulo select que le dirá cuando hay datos leer.

Cuestiones relacionadas