Frage

Ich habe einen kleinen Web-Server-Anwendung ich in Python geschrieben habe, dass einige Daten aus einem Datenbanksystem geht und bekommt und gibt sie an den Benutzer als XML. Das Teil funktioniert gut - ich kann die Python Web-Server-Anwendung von der Kommandozeile aus und ich kann Clients eine Verbindung zu ihm haben und die Daten wieder zu bekommen. Im Moment der Webserver muss ich laufen auf unseren Server als Administrator Benutzer angemeldet sein und ich muss manuell auf den Webserver starten. Ich mag, dass der Web-Server beim Systemstart als Dienst starten und läuft automatisch im Hintergrund haben.

Code Verwenden von Active 's Website und StackOverflow , habe ich eine ziemlich gute Vorstellung davon, wie es weiter gehen über einen Service, und ich glaube, ich sortiert, dass etwas habe - ich installieren und meine Web-Server als Windows-Dienst starten kann. Ich kann aber nicht herausfinden, wie der Dienst wieder zu stoppen. Mein Web-Server von einem BaseHTTPServer erstellt wird:

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

Der serve_forever () -Aufruf, natürlich genug, macht die Web-Server sitzt in einer Endlosschleife und warten Sie auf HTTP-Verbindungen (oder ctrl-Pause keypress, nicht sinnvoll für einen Dienst). Ich bekomme die Idee aus dem Beispielcode oben, dass Ihre main () Funktion soll in einer Endlos-Schleife sitzen und nur aus ihm heraus zu brechen, wenn es quer durch ein „Stopp“ Zustand kommt. Mein Haupt Anrufe serve_forever (). Ich habe eine SvcStop Funktion:

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

Welche genannt zu werden scheint, wenn ich „Python myservice stop“ von der Kommandozeile (I kann eine Debug-Zeile setzen, dass Ausgabe in eine Datei erzeugt), aber nicht beendet tatsächlich den gesamten Service - nachfolgende Aufrufe " python myservice start“gibt mir eine Fehlermeldung:

  

Fehler beim Starten des Service: Eine Instanz   der Dienst bereits ausgeführt wird.

und nachfolgende Aufrufe gibt mir zu stoppen:

  

Fehler beim Stoppen Service: Der Service   kann keine Steuerungsmeldungen annehmen diese   Zeit. (1061)

Ich glaube, ich brauche entweder einigen Ersatz für serve_forever (serve_until_stop_received, oder was auch immer) oder brauche ich einen Weg SvcStop zu modifizieren, so dass es den gesamten Dienst beendet.

Hier ist eine vollständige Liste (ich habe getrimmten includes / Kommentare Platz zu sparen):

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)
War es hilfreich?

Lösung

Das ist, was ich tue:

Statt direkt die Klasse BaseHTTPServer.HTTPServer von Instancing, schreibe ich einen neuen Nachkommen davon, die eine „Stop“ Methode veröffentlicht:

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

Und dann wird bei dem Verfahren SvcStop, die Sie bereits haben, ich nenne das Verfahren die serve_forever () Schleife zu brechen:

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

(self.httpd ist die Instanz von AppHTTPServer (), die den Web-Server implementiert)

Wenn Sie setDaemon () korrekt auf den Hintergrund-Threads und Interrupt korrekt alle Schleifen in dem Dienst, dann wird die Anweisung

exit(0)

in SvcStop () sollte nicht notwendig sein,

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top