2008-09-30 23 views
6

Tengo una pequeña aplicación de servidor web que he escrito en Python que va y obtiene algunos datos de un sistema de base de datos y los devuelve al usuario como XML. Esa parte funciona bien: puedo ejecutar la aplicación de servidor web Python desde la línea de comandos y puedo hacer que los clientes se conecten y obtengan datos. Por el momento, para ejecutar el servidor web, debo iniciar sesión en nuestro servidor como usuario administrador y tengo que iniciar manualmente el servidor web. Quiero que el servidor web se inicie automáticamente en el inicio del sistema como un servicio y se ejecute en segundo plano.Ejecutar un servidor web Python como un servicio en Windows

El uso de código desde el sitio ActiveState 's y StackOverflow, tengo una idea bastante buena de cómo ir sobre la creación de un servicio, y yo creo que tengo que poco ordenadas - Puedo instalar y poner en mi servidor web como una Servicio de Windows. No puedo, sin embargo, descubrir cómo detener el servicio nuevamente. Mi servidor web se crea de una BaseHTTPServer:

server = BaseHTTPServer.HTTPServer(('', 8081), SIMSAPIServerHandler) 
server.serve_forever() 

El serve_forever() llamada, como es natural, hace que el plantón servidor web en un bucle infinito y espera para las conexiones HTTP (o pulsar una tecla ctrl-break, no es útil para un servicio). Me sale la idea del código de ejemplo de arriba que su función main() se supone que se sienta en un bucle infinito y solo salga de ella cuando se trata de una condición de "detención". Mis llamadas principales serve_forever(). Tengo una función SvcStop:

def SvcStop(self): 
    self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 
    exit(0) 

que parece ser llamado cuando lo haga "parada pitón myservice" de la línea de comandos (que se puede poner una línea de depuración de ahí que produce una salida a un archivo), pero no lo hace de hecho salir todo el servicio - posteriores llamadas a "inicio pitón myservice" me da un error:

Error starting service: An instance of the service is already running.

y las llamadas posteriores para detener me da:

Error stopping service: The service cannot accept control messages at this time. (1061)

creo que es necesario o bien algunas re colocación para serve_forever (serve_until_stop_received, o lo que sea) o necesito alguna forma de modificar SvcStop para que detenga todo el servicio.

Aquí está una lista completa (He recortado includes/comentarios para ahorrar espacio):

class SIMSAPIServerHandler(BaseHTTPServer.BaseHTTPRequestHandler): 
    def do_GET(self): 
     try: 
      reportTuple = self.path.partition("/") 
      if len(reportTuple) < 3: 
       return 
      if reportTuple[2] == "": 
       return 
      os.system("C:\\Programs\\SIMSAPI\\runCommandReporter.bat " + reportTuple[2]) 
      f = open("C:\\Programs\\SIMSAPI\\out.xml", "rb") 
      self.send_response(200) 
      self.send_header('Content-type', "application/xml") 
      self.end_headers() 
      self.wfile.write(f.read()) 
      f.close() 
      # The output from CommandReporter is simply dumped to out.xml, which we read, write to the user, then remove. 
      os.unlink("C:\\Programs\\SIMSAPI\\out.xml") 
      return 
     except IOError: 
      self.send_error(404,'File Not Found: %s' % self.path) 



class SIMSAPI(win32serviceutil.ServiceFramework): 
    _svc_name_ = "SIMSAPI" 
    _svc_display_name_ = "A simple web server" 
    _svc_description_ = "Serves XML data produced by SIMS CommandReporter" 

    def __init__(self, args): 
     win32serviceutil.ServiceFramework.__init__(self, args) 
     self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)   

    def SvcStop(self): 
      self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 
      exit(0) 

    def SvcDoRun(self): 
     import servicemanager 
     servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, '')) 

     self.timeout = 3000 

     while 1: 
      server = BaseHTTPServer.HTTPServer(('', 8081), SIMSAPIServerHandler) 
      server.serve_forever() 

def ctrlHandler(ctrlType): 
    return True 

if __name__ == '__main__': 
    win32api.SetConsoleCtrlHandler(ctrlHandler, True) 
    win32serviceutil.HandleCommandLine(SIMSAPI) 

Respuesta

3

Esto es lo que hago:

En lugar de generar ejemplares directamente a la BaseHTTPServer.HTTPServer clase, escribo un nuevo descendiente de ella que publica un "stop" método:

class AppHTTPServer (SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): 
    def serve_forever(self): 
     self.stop_serving = False 
     while not self.stop_serving: 
      self.handle_request() 

    def stop (self): 
     self.stop_serving = True 

Y luego, en el SvcStop método que ya tiene, llamo a ese método para romper el serve_forever() Bucle:

def SvcStop(self): 
    self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 
    self.httpd.stop() 

(self.httpd es la instancia de AppHTTPServer() que implementa el servidor web)

Si utiliza setDaemon() correctamente en los subprocesos de fondo, e interrumpir correctamente todos los bucles de el servicio, entonces la instrucción

exit(0) 

en SvcStop() no debería ser necesario

+0

puede ayudarle con la pregunta en el mismo contexto [aquí] (http://stackoverflow.com/questions/228 14933/make-server-and-console-daemon-as-service-in-windows) –

Cuestiones relacionadas