Question

J'ai une petite application de serveur Web écrite en Python qui récupère des données d'un système de base de données et les renvoie à l'utilisateur au format XML. Cette partie fonctionne bien. Je peux exécuter l’application de serveur Web Python à partir de la ligne de commande et permettre aux clients de s'y connecter et de récupérer les données. À l'heure actuelle, pour exécuter le serveur Web, je dois être connecté à notre serveur en tant qu'utilisateur 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.

Utilisation du code du site ActiveState et StackOverflow , j'ai une bonne idée de la marche à suivre sur la création d’un service, et je pense avoir réglé le problème - je peux installer et démarrer mon serveur Web en tant que service Windows. Cependant, je ne peux pas trouver comment arrêter le service. Mon serveur Web est créé à partir d’un serveur BaseHTTPServer:

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

L’appel serve_forever () oblige, bien entendu, le serveur Web à s’asseoir dans une boucle infinie et à attendre les connexions HTTP (ou une touche Ctrl-break, inutile pour un service). L’exemple de code ci-dessus me donne l’idée que votre fonction main () est supposée s’asseoir dans une boucle infinie et ne s’en échapper que lorsqu’elle tombe sur un "stop". état. Mes appels principaux servent_forever (). J'ai une fonction SvcStop:

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

Ce qui semble être appelé lorsque je fais "python myservice stop". à partir de la ligne de commande (je peux y insérer une ligne de débogage générant une sortie vers un fichier) mais ne quittant pas le service complet - appels suivants à "python myservice start" me donne une erreur:

  

Erreur de démarrage du service: une instance de   le service est déjà en cours d'exécution.

et les appels d'arrêt suivants me donnent:

  

Erreur lors de l'arrêt du service: le service   ne peut pas accepter les messages de contrôle à ce stade   temps. (1061)

Je pense que j'ai besoin d'un remplacement pour serve_forever (serve_until_stop_received ou quoi que ce soit d'autre) ou d'un moyen de modifier SvcStop afin qu'il arrête l'ensemble du service.

Voici une liste complète (j'ai coupé les inclus / commentaires pour économiser de 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)
Était-ce utile?

La solution

C'est ce que je fais:

Au lieu d’instancier directement la classe BaseHTTPServer.HTTPServer, j’écris un nouveau descendant qui publie un " arrêt " méthode:

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 ensuite, dans la méthode SvcStop que vous avez déjà, j'appelle cette méthode pour rompre la boucle serve_forever ():

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 correctement setDaemon () sur les threads d'arrière-plan et interrompez correctement toutes les boucles du service, l'instruction

exit(0)

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top