2008-09-30 10 views
6

J'ai une petite application de serveur Web que j'ai écrite en Python qui va chercher des données d'un système de base de données et les renvoie à l'utilisateur en XML. Cette partie fonctionne bien - je peux lancer l'application serveur web Python depuis la ligne de commande et je peux avoir des clients qui s'y connectent et récupèrent des données. Pour le moment, pour lancer le serveur web, je dois être connecté à notre serveur en tant qu'administrateur et je dois démarrer manuellement le serveur web. Je souhaite que le serveur Web démarre automatiquement au démarrage du système en tant que service et s'exécute en arrière-plan.Exécution d'un serveur Web Python en tant que service sous Windows

En utilisant du code à partir du site de ActiveState et StackOverflow, j'ai une assez bonne idée de la façon d'aller sur la création d'un service, et je pense que j'ai que peu triée - je peux installer et démarrer mon serveur web en tant que Service Windows Je ne peux pas, cependant, comprendre comment arrêter le service encore. Mon serveur web est créé à partir d'un BaseHTTPServer:

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

L'appel serve_forever(), assez naturellement, rend le sit serveur web dans une boucle infinie et attendre les connexions HTTP (ou pression d'une touche ctrl-break, pas utile pour un service). Je reçois l'idée de l'exemple de code ci-dessus que votre fonction main() est supposée s'asseoir dans une boucle infinie et n'en sortir que lorsqu'elle traverse une condition "stop". Mes appels principaux serve_forever(). J'ai une fonction SvcStop:

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

Ce qui semble s'appeler quand je fais « arrêt python myservice » de la ligne de commande (je peux mettre une ligne de débogage là-dedans qui produit une sortie dans un fichier), mais ne en fait sortir tout le service - les appels suivants à « début python myservice » me donne une erreur:

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

et les appels suivants pour arrêter me donne:

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

Je pense que je dois soit une re placement pour serve_forever (serve_until_stop_received, ou peu importe) ou j'ai besoin d'un moyen de modifier SvcStop afin qu'il arrête tout le service.

Voici une liste complète (je l'ai parés includes/commentaires pour économiser l'espace):

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) 

Répondre

3

Voici ce que je fais:

Au lieu de instanciation directement la BaseHTTPServer.HTTPServer de classe, j'écris un nouveau descendant de celui-ci qui publie une méthode « stop »:

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 

Et puis, dans la méthode SvcStop que vous avez déjà, j'appelle cette méthode pour briser le serve_forever() Boucle:

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

(self.httpd est l'instance de AppHTTPServer() qui implémente le serveur Web)

Si vous utilisez setDaemon() correctement sur les fils de fond, et interrompre correctement toutes les boucles en le service, l'instruction

exit(0) 

dans SvcStop() ne devrait pas être nécessaire

+0

peut vous aider à la question dans le même contexte [ici] (http://stackoverflow.com/questions/228 14933/make-server-et-console-daemon-as-service-in-windows) –

Questions connexes