2010-09-22 12 views
5

Actualmente estoy trabajando en la exposición de datos del sistema heredado en la web. Tengo una aplicación de servidor (heredada) que envía y recibe datos a través de UDP. El software usa UDP para enviar actualizaciones secuenciales a un conjunto dado de variables en (casi) tiempo real (actualizaciones cada 5-10 ms). por lo tanto, no necesito capturar todos los datos UDP, basta con recuperar la última actualización.¿Cómo se sirven los datos de la secuencia UDP a través de HTTP en Python?

Para exponer estos datos en la web, estoy considerando construir un servidor web liviano que lea/escriba datos UDP y expone estos datos a través de HTTP.

Como tengo experiencia con Python, estoy pensando en usarlo.

La pregunta es la siguiente: ¿cómo puedo (continuamente) leer datos de UDP y enviar capturas de pantalla a través de TCP/HTTP bajo demanda con Python? Básicamente, estoy tratando de construir un tipo de adaptador "UDP2HTTP" para interactuar con la aplicación heredada para que no tenga que tocar el código heredado.

Sería preferible una solución que sea compatible con WSGI. ¡Por supuesto que cualquier consejo es muy bienvenido y MUCHO apreciado!

+3

No hay "continuo" en HTTP. Por definición. No puede haber ¿Que estas pidiendo? ¿Una versión milagrosa del protocolo HTTP que de alguna manera no sigue las reglas HTTP y en su lugar se comporta como UDP? –

+0

Gracias por su preocupación. Sé que tal cosa no existe. Para aclarar: mi problema es tratar de leer instantáneas de datos UDP a través de HTTP. No estoy tratando de hacer HTTP "continuo" (la pregunta también fue editada) – jsalonen

+0

Una buena estructura para usar sería tener algún tipo de modelo de las variables en una aplicación web implementada de alguna manera. La información UDP actualiza ese modelo (es decir, la aplicación web lo escucha) pero no dice nada de HTTP para actualizar. Cualquier recuperación de HTTP solo lee una instantánea del estado actual de esas variables (y recuerda deshabilitar el almacenamiento en caché de las páginas generadas). –

Respuesta

3

El software usa UDP para enviar actualizaciones secuenciales a un conjunto dado de variables en (casi) tiempo real (actualizaciones cada 5-10 ms). por lo tanto, no necesito capturar todos los datos UDP: es suficiente recuperar la última actualización

Lo que debe hacer es esto.

Paso 1.

crear una aplicación Python que recoge los datos UDP y lo almacena en un archivo. Crea el archivo usando la notación XML, CSV o JSON.

Esto funciona independientemente como algún tipo de daemon. Este es tu oyente o coleccionista.

Escriba el archivo en un directorio desde el cual Apache u otro servidor web pueda descargarlo trivialmente. Elija nombres y rutas de directorio con prudencia y listo.

Listo.

Si quieres resultados más elegantes, puedes hacer más. No es necesario, ya que ya está hecho.

Paso 2.

construir una aplicación web que permite a alguien para solicitar estos datos siendo acumulada por el oyente UDP o colector.

Utilice un marco web como Django para esto. Escribe lo menos posible. Django puede servir archivos planos creados por tu oyente.

Ya ha terminado. De nuevo.

Algunas personas piensan que las bases de datos relacionales son importantes. Si es así, puedes hacer esto. A pesar de que ya has terminado.

Paso 3.

Modificar la recogida de datos para crear una base de datos que el ORM de Django puede consultar. Esto requiere algo de aprendizaje y algunos ajustes para obtener un modelo ORM ordenado y simple.

Luego escriba su aplicación Django final para servir los datos UDP que su oyente recoge y carga en su base de datos Django.

+0

Gracias por su respuesta elaborada. Pero no es necesario ser grosero, amigo. Soy muy consciente de que estoy lidiando con un problema complejo, gracias. Estuve de acuerdo con usted en que, en plazos más largos, la persistencia, el caché, etc. se convierten en problemas. En este momento, sin embargo, solo necesito una prueba de concepto. En este punto, cualquier código de trabajo, incluso feo y hacky, que me demuestre cómo leer instantáneas de datos UDP y enviarlos a través de HTTP es suficiente. – jsalonen

+0

Tenga en cuenta también que he editado mi pregunta para ser más específico! – jsalonen

+0

Lo siento, parece grosero. La pregunta, tal como se planteó originalmente, era demasiado vaga y estaba demasiado llena de agujeros para ser tomada en serio al pie de la letra. Sin ** detalles ** y ** detalles ** el enfoque implícito no podría funcionar. Evite preguntas vagas sin ** detalles ** o ** detalles **. –

6

Twisted sería muy adecuado aquí. Es compatible con muchos protocolos (UDP, HTTP) y su naturaleza asíncrona hace posible transmitir datos UDP directamente a HTTP sin dispararse en el pie con el código de enhebrado (de bloqueo). También es compatible con wsgi.

5

Aquí hay una aplicación rápida de "prueba de concepto" utilizando el marco trenzado. Esto supone que el servicio UDP heredado está escuchando en localhost: 8000 y comenzará a enviar datos UDP en respuesta a un datagrama que contiene "Enviarme datos". Y que los datos son 3 enteros de 32 bits. Además es capaz de responder a un "HTTP GET /" en el puerto 2080.

Se podría empezar con este twistd -noy example.py:

example.py

from twisted.internet import protocol, defer 
from twisted.application import service 
from twisted.python import log 
from twisted.web import resource, server as webserver 

import struct 

class legacyProtocol(protocol.DatagramProtocol): 
    def startProtocol(self): 
     self.transport.connect(self.service.legacyHost,self.service.legacyPort) 
     self.sendMessage("Send me data") 
    def stopProtocol(self): 
     # Assume the transport is closed, do any tidying that you need to. 
     return 
    def datagramReceived(self,datagram,addr): 
     # Inspect the datagram payload, do sanity checking. 
     try: 
      val1, val2, val3 = struct.unpack("!iii",datagram) 
     except struct.error, err: 
      # Problem unpacking data log and ignore 
      log.err() 
      return 
     self.service.update_data(val1,val2,val3) 
    def sendMessage(self,message): 
     self.transport.write(message) 

class legacyValues(resource.Resource): 
    def __init__(self,service): 
     resource.Resource.__init__(self) 
     self.service=service 
     self.putChild("",self) 
    def render_GET(self,request): 
     data = "\n".join(["<li>%s</li>" % x for x in self.service.get_data()]) 
     return """<html><head><title>Legacy Data</title> 
      <body><h1>Data</h1><ul> 
      %s 
      </ul></body></html>""" % (data,) 

class protocolGatewayService(service.Service): 
    def __init__(self,legacyHost,legacyPort): 
     self.legacyHost = legacyHost # 
     self.legacyPort = legacyPort 
     self.udpListeningPort = None 
     self.httpListeningPort = None 
     self.lproto = None 
     self.reactor = None 
     self.data = [1,2,3] 
    def startService(self): 
     # called by application handling 
     if not self.reactor: 
      from twisted.internet import reactor 
      self.reactor = reactor 
     self.reactor.callWhenRunning(self.startStuff) 
    def stopService(self): 
     # called by application handling 
     defers = [] 
     if self.udpListeningPort: 
      defers.append(defer.maybeDeferred(self.udpListeningPort.loseConnection)) 
     if self.httpListeningPort: 
      defers.append(defer.maybeDeferred(self.httpListeningPort.stopListening)) 
     return defer.DeferredList(defers) 
    def startStuff(self): 
     # UDP legacy stuff 
     proto = legacyProtocol() 
     proto.service = self 
     self.udpListeningPort = self.reactor.listenUDP(0,proto) 
     # Website 
     factory = webserver.Site(legacyValues(self)) 
     self.httpListeningPort = self.reactor.listenTCP(2080,factory) 
    def update_data(self,*args): 
     self.data[:] = args 
    def get_data(self): 
     return self.data 

application = service.Application('LegacyGateway') 
services = service.IServiceCollection(application) 
s = protocolGatewayService('127.0.0.1',8000) 
s.setServiceParent(services) 

Afterthought

Este no es un diseño de WSGI. La idea de esto sería utilizar para ejecutar este programa desmemoriado y tener su puerto http en una IP local y apache o similar a las solicitudes de proxy. Podría ser refactorizado para WSGI. Fue más rápido golpear de esta manera, más fácil de depurar.

+0

Gracias MUCHO por la respuesta con el código real. Me he tropezado muchas veces sin saber realmente cuán difícil es de usar. Este código brinda un código de prueba de concepto que puedo diseminar y usar como punto de partida. – jsalonen

+0

De nada. Creo que uno de los inconvenientes con retorcido es una curva de aprendizaje empinada y puede haber una gran barrera de esfuerzo antes de tener suficiente concepto de trabajo para comenzar mejoras iterativas. – MattH

Cuestiones relacionadas